【问题标题】:Which pattern should I break?我应该打破哪种模式?
【发布时间】:2015-05-19 16:07:34
【问题描述】:

不要重复自己 或者 封装?

假设我创建了以下内容:

  1. 实现 IList 的接口 IMask。
  2. 实现 IMask 的 Class Spot。
  3. 一个包含几个整数和一个 Spot 作为字段的类标记。

我想让 Marker 实现 IMask 接口。但后来我会重复自己(最后检查代码) 或者我可以在 Marker 公众中成为我的 Spot。但随后我将公开我的课程的实现。 或者我可以从 Spot 继承我的 Spot,但这不是理想的解决方案,因为从语义上讲,标记不是 Spot 的特定类型。

如果我创建另一个具有 Spot 作为字段的类,并且我想再次实现 IMask 接口,该怎么办? 我会再次重复自己。 那么,我应该如何进行呢?我应该公开 Spot 中的列表吗?然后将标记中的 Spot 公开? 还是我应该重复通话?

interface IMask : IList<Point>
    {
        public void MoveTo(Point newCenter);
        // ... other Methods
    }

    public class Spot : IMask
    {
        List<Point> points;

        public void DoSpotyStuff()
        {
            // blabla
        }

        // Other methods
        // ...
        // Finally the implementation of IMask
        public void MoveTo(Point newCenter)
        {
            // blabla
        }

        // And of course the IList methods
        public void Add(Point newPoint)
        {
            points.Add(newPoint);
        }
    }

    public class Marker : IMask
    {
        private Spot mySpot;
        private int blargh;
        // Other fields

        public void MarkeryMethod()
        {
            // Blabla
        }

        // HERE IS THE PROBLEM: Should I do this and repeat myself
        public void MoveTo(Point newCenter) { mySpot.MoveTo(newCenter); }

        // And here I'm REALLY starting to repeat myself
        public void Add(Point newPoint) { mySpot.Add(newPoint); }
    }

观察: 接口 IMask 不是从 List 继承的。它正在实现 IList 接口,而后者又是implements ICollection, IEnumerable 假设 Marker 在语义上不是特殊的 Spot。因此,即使我可以从 Spot 继承并解决问题,它也不是最好的解决方案。

【问题讨论】:

  • 我没有从 IList 继承。 IList 是一个接口,我的意思是:每当一个类实现 IMask 时,它也实现了 IList。
  • 为什么你的Marker 不继承自Spot,因为听起来你的标记是一个专门的位置
  • James,在链接的问题中,用户从 List 继承,这是一个实现 IList 接口的类。我不这样做。我的接口只是在实现另一个接口。
  • IMask 只是带​​有MoveTo 方法的List&lt;Point&gt; 吗?如果是这样,为什么不将MoveTo 设为扩展方法?

标签: c# inheritance interface


【解决方案1】:

接口是建立一种契约,实现它的类将具有此方法。因此,您可以做一个抽象/基类来实现您的接口,然后标记和 Spot 类可以从基类继承,一切就绪,一切顺利。

public abstract class BaseClass : IMask {...}

public class Marker : BaseClass{...}

public class Spot : BaseClass{...}

2020 年 1 月更新: 在 C#8 中,您可以使用带有实现的默认接口方法(这基本上会扼杀抽象类的用例),您可以在这里查看:https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/default-interface-methods

【讨论】:

    【解决方案2】:

    在我看来,您的选择应该基于您期望应用程序的增长方式,即向前兼容性。

    如果您认为 Marker 会发展,例如也许有一天它会包含多个 Spot 或多个支持 IMask 的对象,然后重复自己是要走的路,因为您将要协调对 MoveTo 和 Add 的调用以包含所有对象在 Marker 中,你会很高兴在 Marker 中有一个间接层。

    如果您认为 Spot 会发展,例如如果 Spot 将添加更多方法,例如 ChangeSize 或 Remove,也许最好的办法是将 Spot 公开为 IMask 类型的 Marker 的公共属性。这样一来,无需编写额外的包装代码即可立即公开新属性。

    【讨论】:

      【解决方案3】:
      interface IMask : IList<System.Drawing.Point>
      {
          public void MoveTo(System.Drawing.Point newCenter);
          // ...
          public void 
      }
      public class Mask : IMask
      {
          // ...
      }
      public class Spot
      {
          public Mask Mask = new Mask();
          // ...
      }
      public  class Marker
      {
          public Mask Mask = new Mask();
          /// ...
      }
      

      为方便起见,您最好使用属性。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-10-09
        • 2011-10-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-30
        • 1970-01-01
        • 2013-01-03
        相关资源
        最近更新 更多