【问题标题】:Is it appropriate to have multiple identical classes with different names?有多个具有不同名称的相同类是否合适?
【发布时间】:2014-05-03 17:14:06
【问题描述】:

我有一个关于命名具有相似功能的多个类的问题。我正在开发一个科学 API,并拥有以下类/接口:

public interface IRange<T>{
    T Minimum {get;}
    T Maximum {get;}
    // A few other methods that aren't important
}

public class Range<T> : IRange<T> where T: IComparable<T> {
    public T Minimum {get; protected set;}
    public T Maximum {get; protected set;}

    public Range(T minimum, T maximum) {
        Minimum = minimum;
        Maximum = maximum;
    }
}

对于我的 API,我经常使用 double 范围(即 Range&lt;double&gt;),因此我创建了另一个名为 MassRange 的类。这个类还有一些新的构造函数和属性,如下所示:

public class MassRange : Range<double>, IRange<double> {
    public double Width { get { return Maximum - Minimum;} }
    public double Mean { get { return (Maximum + Minimum) / 2.0;} }

    public MassRange(double mean, MassTolerance width) {
        Minimum = mean - width.Value;  // pseudo-code
        Maximum = mean + width.Value;
    }
}

从概念上讲,我还有另一种类型的Range&lt;double&gt;,称为MzRange,它与MassRange 共享所有相同的结构和功能,但我想在API 中保持独立。它们的行为完全相同并存储相同类型的数据,但就科学而言,它们是不同且截然不同的。

所以我考虑将MassRange 类重命名为更通用的名称DoubleRange,然后将MassRange : DoubleRangeMzRange : DoubleRange 设计成这样:

public MzRange : DoubleRange, IRange<double> {}

public MassRange : DoubleRange, IRange<double> {}

但我并不真正关心 DoubleRange 这个名字,也不想通过我的 API 公开它。公开具有相同功能的两种不同类型是否合适?我是否应该为DoubleRange 取一个更好的名字而放弃MzRangeMassRange?我可以将DoubleRange 设为内部或其他东西,这样它就不会通过 API 公开但仍然可以使用?

这似乎是Extension Properties 的情况,但我知道它们目前不存在。

【问题讨论】:

    标签: c# inheritance nomenclature


    【解决方案1】:

    您似乎没有任何理由无法使用标准 extension methods 完成此任务:

    public static double GetWidth(this IRange<double> range) {
        return range.Maximum - range.Minimum;
    }
    
    public static double GetMean(this IRange<double> range) {
        return (range.Maximum + range.Minimum) / 2.0;
    }
    

    然后你可以从IRange的任何实现中调用它:

    var massRange = ...
    var mean = massRange.GetMean();
    

    我知道它可能没有扩展属性的语法吸引力,但它是一个干净的解决方案,无需创建 DoubleRange 类。

    【讨论】:

    • 我绝对同意你在这里所说的。他们应该以实现 Linq 的方式实现他们的需求。很多通用接口和很多扩展方法。 +1
    • 这适用于属性,但对我添加到 DoubleRange 的新构造函数没有帮助。
    • @Moop 它不会为您提供任何构造函数,但大概您在 MassRangeMzRange 类上有不同的构造函数,而您的 DoubleRange 无论如何都不会有,对吧? MzRange 是否接受MzTolerance?当然,您可以根据您的确切需求创建一个静态工厂方法,但从问题中并不完全清楚那将是什么。
    【解决方案2】:

    这是绝对合适的。除了逻辑上的区别之外,它还使您有可能在将来独立地发展这两个类。

    即使大象和鸟类都是动物(都继承自动物)并且都具有相同的属性集(它们不添加或覆盖成员),您可能希望将来为鸟类添加 Fly 方法。 我假设名为 Dumbo 的大象在现实世界中不存在 :-)

    【讨论】:

    • 你为什么没有一个 Animal 类来继承 ElephantBird 呢? BirdElephant 类并不相同,而是它们都继承自 Animal,其中包含基本属性,如 WeightHeight 或所有动物的一些共同属性。您不会想在整个地方都创建具有重复属性的BirdElephant;那将是一个糟糕的设计。
    • @MichaelJ.Gray 我能明白 Oliver 在说什么,但我想 ElephantBird 可能不是这里最好的比喻。 ElephantCar 可能会更好。两者都有一定的体重和身高,甚至都有一个树干。但是,它们是如此不同,因此可能需要设计完全不同的层次结构。不过,我可能会围绕它们设计功能界面(例如Car : IHasWheels)来描述您实际上可以用它们做什么
    • @MichaelJ.Gray:“大象和鸟类都是动物”我的意思是它们都继承自animal。 “两者都具有相同的属性集”是指除了从animal 继承的成员之外,它们不提供其他成员。
    • 可以创建一个 Bird 和 Elephant 类,让它们继承自 Animal 并保留它。不是让两个类都继承 Animal,然后让它们分别实现完全相同的功能。
    • @p.s.w.g 我同意功能接口在这一点上是有益的。感谢您举这个例子,它更有意义。
    【解决方案3】:

    具有完全相同功能的两种类型是不合适的,因为对一种类型进行的任何更改都需要对另一种进行。

    除非您知道 MassRangeMzRange 将在未来的某个时候进行区分,为 DoubleRange 提供更好的名称,而放弃 MassRange/MzRange 是要走的路。即便如此,任何共享功能都需要放在父类型中。

    您可以随时提供一些syntactic sugar 来帮助用户。例如,您可以创建名为MassRangeMzRange 的“哑”类,它们只是扩展DoubleRange。我会保留原始的、命名良好的类,以鼓励用户使用它,但如果你真的想隐藏它,只需使用 protected 访问器而不是 public

    【讨论】:

      猜你喜欢
      • 2011-09-16
      • 1970-01-01
      • 2021-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-20
      • 2013-02-16
      相关资源
      最近更新 更多