为了账号安全,请及时绑定邮箱和手机立即绑定

定义相似职责的接口

定义相似职责的接口

C#
慕村9548890 2021-04-05 21:22:13
假设我有一个interface ICanRotateWithinLimitedRange。有两种方法可以指定对象可以旋转的范围:可以指定StartingAngle和EndingAngle。或者,可以指定StartingAngle和RotationRangeInDegrees。(假设这些角度是相对于天顶定义的。)在这两种情况下,StartingAngle都是必要的信息,此外还应指定EndingAngle xor RotationRangeInDegrees。我认为,ICanRotateWithinLimitedRange如下定义是错误的:public interface ICanRotateWithinLimitedRange{    float StartingAngle { get; }    float EndingAngle { get; }    float RotationRangeInDegrees { get; }}实际上应该有两个接口,用于两种可以指定旋转范围的不同方式。但是,该名称ICanRotateWithinLimitedRange适用于两个接口,因此如何适当命名接口以区分这两个接口?
查看完整描述

2 回答

?
慕姐4208626

TA贡献1852条经验 获得超7个赞

尚不清楚为什么这是一个接口。它代表有效旋转的范围,而不是旋转任何东西的能力。接口通常最能代表功能,而不仅仅是数据对象,IMO。很难看到这里所表示的数据如何有多种有用的表示形式。


以任何一种形式创建的旋转都可以表示所有三个值,因此我只需要编写带有工厂方法的单独的类或结构来表示两种不同的创建实例的方式:


// Note: You may well want to make this a struct instead.

public sealed class RotationRange

{

    public float Start { get; }

    public float End { get; }

    public float Range => End - Start;


    private RotationRange(float start, float end)

    {

        Start = start;

        End = end;

    }


    public bool IsValid(float angle) => angle <= Start && angle < End;


    public static RotationRange FromStartAndEnd(float start, float end) =>

        new Rotation(start, end);


    public static RotationRange FromStartAndRange(float start, float range) =>

        new Rotation(start, start + range);

}

该名称可能需要改变-这不是完全清楚怎么在这里的意思......它可能是Start和End真正应该MinimumAngle和MaximumAngle例如,它的奇使用Range的范围的长度和范围本身。您可能还需要添加单位。(您的问题中具有“学位”,但仅适用于一种性质,而大概适用于所有这些性质。)


哦,您可能想进行一堆验证:)


您可能有一个单独的接口,该接口使用该类作为参数或返回值。例如:


public interface IRotatable

{

    RotationRange RotationRange { get; }

    // This must be valid according to RotationRange

    void Rotate(float angle);

}

那代表了旋转的实际能力。


查看完整回答
反对 回复 2021-04-17
?
翻过高山走不出你

TA贡献1875条经验 获得超3个赞

有两种方法可以指定对象可以旋转的范围


我将假设一个人总是可以在这两种方法之间进行选择。


执行旋转(Rotate())的方法应独立于允许旋转的参数。


注意:当然,从某种意义上讲它是相关的,因为它知道在哪里可以找到所需的参数,但是该方法应该可以与用户选择的两个参数集中的一个无关。


因此,该轮换具有简化的签名:


public void Rotate(IRotationParameters parameters)

这使您能够开发方法主体而无需关心如何定义参数。


随着方法主体的发展,挑战就变成了定义参数(任一种方式)。


由于您已经在使用接口,因此让我们扩展该方法:


publc interface IRotationParameters

{

     float StartingAngle { get; }

     float EndingAngle { get; }

     float RotationAngle { get; }

}

假设任何一个IRotationParameters都将始终暴露所有三个变量,那么您将始终能够实现轮换(无论如何)。


假设我们有三个开发人员,每个开发人员都喜欢一种特定的轮换方法。


开发人员A首选此start+angle方法。

开发人员B更喜欢这种start+end方法。

开发该Rotate()方法的Dev C具有未知的偏好。

如何满足开发人员A:


使用此类:


public class RotationParametersFromStartAndAngle : IRotationParameters

{

     public float StartingAngle { get; private set; }

     public float EndingAngle { get; private set; }

     public float RotationAngle { get; private set; }   


     public RotationParametersFromStartAndAngle(float start, float angle)

     {

         this.StartingAngle = start;

         this.RotationAngle = angle;

         this.StartingAngle = start + angle;

     } 

}

如何满足开发人员B:


使用此类:


public class RotationParametersFromStartAndEnd : IRotationParameters

{

     public float StartingAngle { get; private set; }

     public float EndingAngle { get; private set; }

     public float RotationAngle { get; private set; }   


     public RotationParametersFromStartAndEnd (float start, float end)

     {

         this.StartingAngle = start;

         this.StartingAngle = end;

         this.RotationAngle = end - start;

     } 

}

如何满足开发人员C:


开发人员C将始终感到满意,因为IRotationParameters这两种方法都可以为您提供便利。他可以随心所欲地开发自己的方法(即使他是一个怪人,他也认为应该使用第三种“角度+末端”方法)。


评论


我使用了两个不同的参数类。您还可以将单个类与两个静态“构造”方法一起使用。这样就不需要接口了,因为您只使用一个类。

您可以具有一个EndingAngle或RotationAngle为计算所得的属性,而不是在构造函数中对其进行计算。

这里有许多可能的变化。我试图坚持使用接口(您已经在使用它)的简单明了的接口。


查看完整回答
反对 回复 2021-04-17
  • 2 回答
  • 0 关注
  • 153 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信