我应该打破哪种模式?

问题描述 投票:4回答:3

不要重复自己要么封装?

假设我创建了以下内容:

  1. 实现IList的接口IMask。
  2. 实现IMask的Cla​​ss Spot。
  3. 一个包含一些整数和一个点作为字段的类标记。

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

如果我创建另一个具有Spot作为字段的类,又想实现IMask接口,该怎么办?我会再重复一次。那么,我应该如何进行?我应该将Spot中的列表公开吗?然后将Marker中的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继承并解决问题,也不是最好的解决方案。

c# inheritance interface
3个回答
6
投票

接口是建立一种契约,该契约将实施它的类将具有此方法。因此,您可以做的是一个实现您的Interface的抽象类/基类,然后Marker和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


1
投票

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

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

[如果您认为Spot将会发展,例如如果Spot将添加更多方法,例如ChangeSize或Remove,则最好的办法是将Spot作为IMask类型的Marker的公共属性公开。这样,新属性将立即公开,而无需编写其他包装代码。


0
投票
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();
    /// ...
}

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

© www.soinside.com 2019 - 2024. All rights reserved.