定义类似职责的接口

时间:2018-04-13 09:24:42

标签: c# interface

假设我有一个界面ICanRotateWithinLimitedRange。有两种方法可以指定对象可以旋转的范围:

  1. 可以指定StartingAngleEndingAngle
  2. 或者,可以指定StartingAngleRotationRangeInDegrees
  3. (假设这些角度是相对于天顶定义的。)

    在这两种情况下,StartingAngle都是必要的信息,此外还应指定EndingAngle xor RotationRangeInDegrees。在我看来,将ICanRotateWithinLimitedRange定义如下是错误的:

    public interface ICanRotateWithinLimitedRange
    {
        float StartingAngle { get; }
        float EndingAngle { get; }
        float RotationRangeInDegrees { get; }
    }
    

    实际上应该有两个接口,用于指定旋转范围的两种不同方式。

    但是,名称ICanRotateWithinLimitedRange适用于两个接口,因此如何正确命名接口以区分这两个接口?

2 个答案:

答案 0 :(得分:4)

目前尚不清楚为什么这是一个界面。它表示有效旋转的范围,而不是旋转任何东西的能力。接口通常最好代表功能,而不仅仅是数据对象,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);
}

名称可能需要更改 - 它不是完全清除这里的含义...... StartEnd可能真的应该MinimumAngle例如,MaximumAngleRange对范围的长度和范围本身都很奇怪。您可能还想添加单位。 (你的问题中有“度”,但只有一个属性,但大概适用于所有属性。)

哦,你可能想要一堆验证:)

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

public interface IRotatable
{
    RotationRange RotationRange { get; }
    // This must be valid according to RotationRange
    void Rotate(float angle);
}

这表示实际旋转的能力。

答案 1 :(得分:0)

  

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

我假设人们可以始终在这两种方法之间做出选择。

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

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

因此,旋转具有简化的签名:

public void Rotate(IRotationParameters parameters)

这使您可以开发方法体,而无需关心如何定义参数。

随着方法体的发展,挑战就是定义参数(无论哪种方式)。

由于您已经在使用接口,因此我们可以扩展这种方法:

publc interface IRotationParameters
{
     float StartingAngle { get; }
     float EndingAngle { get; }
     float RotationAngle { get; }
}

假设任何IRotationParameters将始终公开所有三个变量,您始终能够实现轮换(无论如何)。

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

  • Dev A更喜欢start+angle方法。
  • Dev B更喜欢start+end方法。
  • 开发Rotate()方法的Dev C有一个未知的偏好。

如何满足Dev 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;
     } 
}

如何满足Dev 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;
     } 
}

如何满足Dev C:

Dev C将始终得到满足,因为IRotationParameters有助于两种方法。他可以随心所欲地发展他的方法(即使他是一个认为应该使用第三个&#34;角度+结束&#34;方法的怪人)。

  

<强>说明

     
      
  • 我使用了两个不同的参数类。你也可以使用一个带有两个静态&#34;构造的单个类&#34;方法。因为您只使用一个类,所以您不需要接口。
  •   
  • 您可以将EndingAngleRotationAngle作为计算属性,而不是在构造函数中计算它。
  •   
  • 这里可能有很多变化。我试图坚持使用一个简单明了的接口(你已经在使用接口)。
  •