我应该打破哪一种模式?

本文关键字:模式 哪一种 我应该 | 更新日期: 2023-09-27 17:49:51

不要重复自己或封装?

假设我创建了以下内容:

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

我想让Marker实现IMask接口。但那样我就会重复我自己(最后检查代码)或者我也可以在Marker的公共空间里找到我的Spot。但这样我就暴露了类的实现。或者我可以从Spot继承我的Spot,但这不是理想的解决方案,因为从语义上讲,Marker不是Spot的特定类型。

如果我创建另一个类,有一个点作为一个字段,我想,再一次,实现IMask接口?我会再重复一遍。那么,我该怎么做呢?我应该在Spot内公开列表吗?然后把Spot in Marker公开吗?还是我再打一遍?

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接口,该接口又实现了ICollection、IEnumerable假定Marker在语义上不是特殊类型的Spot。所以,即使我可以从Spot继承并解决这个问题,这也不是最好的解决方案。

我应该打破哪一种模式?

接口是建立一种契约,实现它的类将具有这些方法。所以你可以做的是一个抽象/基类实现你的接口,然后类Marker和Spot可以从基类继承,你都设置好了,一切就绪。

public abstract class BaseClass : IMask {...}
public class Marker : BaseClass{...}
public class Spot : BaseClass{...}

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

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

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

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

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

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