从派生类更改基类的正确方法

时间:2017-08-22 21:26:18

标签: c# inheritance design-patterns

我正在尝试设计几个基础绘图类,我可以从中继承和定义复杂的绘图。

如您所见,LineDrawingCompoundDrawing派生自抽象的Drawing类。 CompoundDrawing有一个内部List<Drawing>,它允许我们存储任意数量的Drawing个对象,并定义更复杂的图形。

public abstract class Drawing
{       
    public bool CanBeRotated 
    {
       get; 
       set;
    }

    private float m_rotation;
    public float Rotation
    {
        get 
        { 
           return m_rotation;
        }
    }

    protected Drawing()
    {
        CanBeRotated = true;
    }

    public void Rotate(float degree)
    {
        if (CanBeRotated)
            m_rotation = degree;
    }
}

public sealed class LineDrawing : Drawing
{
    private readonly Line m_line;

    public Line Line
    {
        get
        {
           return m_line;
        }
    }

    public LineDrawing(Line line)
    {
        m_line = line;
    }
}

public class CompoundDrawing : Drawing
{
    protected IList<Drawing> m_drawings;

    protected CompoundDrawing(IList<Drawing> drawings)
    {
        m_drawings = new List<Drawing>(drawings);
    }
}

假设我要定义一个派生自CompoundDrawing的RectangleDrawing。

public class RectangleDrawing : CompoundDrawing
{
    public RectangleDrawing(IList<LineDrawing> lineDrawings) : base(lineDrawings)
    {
        foreach(var line in lineDrawings)
        {
            line.CanBeRotated = false;
        }
    }    
}

现在我在这里面临一个问题!显然,我不希望这个新类中的LineDrawing对象是可旋转的!但是我不确定在这个模式中我应该设置哪个!

2 个答案:

答案 0 :(得分:0)

我会考虑采用不可变的方法:

public abstract class Drawing
{ 
    //some shapes might not be rotable or rotation
    //simply doesn't make sense: circle      
    public virtual bool CanBeRotated => true;

    public Drawing Rotate(float degree)
    {
        //Don't mutate this, return a new
        //rotated instance.
        if (!CanBeRotated) return this;
        return rotate(float);
    }

    //let each concrete type handle its own rotation.
    protected abstract Drawing rotate(float);

    //etc.
}

不变性会给你带来什么?好吧,谁在乎是否有人试图旋转你的复合物体的单独线?他们不会改变任何有意义的东西,因为没有什么可以改变,他们只会获得一个不属于原始复合对象的旋转线。

CompoundDrawing轮换逻辑相当简单:

protected override Drawing rotate(float degeee)
   //Note I'm passing in an IEnumerable<Line> instead of an IList<>
   //Why the need of an IList<>, don't burden the API with unecessary 
   //constraints.
    => new Rectange(lines.Select(l => l.Rotate(degree)));

所有这些都说,我建议您将构建块更改为PointLine似乎是一个奇怪的选择。这样,所有形状都是由特定顺序的点组成的复合图形。绘制任何形状只需按顺序连接点,旋转只需旋转每个点等。

答案 1 :(得分:0)

我将Rotate移动到它自己的界面,因为它不适用于所有类型的绘图。

public interface IRotate
{
    void Rotate(float degree);
}

public class SquareDrawing : Drawing, IRotate
{
    public void Rotate(float degree)
    {
         //actual code to rotate the drawing
    }
}

public class RectangleDrawing : CompoundDrawing
{
     public RectangleDrawing(IList<LineDrawing> lineDrawings) : base(lineDrawings)
     {
        foreach(var line in lineDrawings)
        {
            if (line is IRotate)
            {
                 ((IRotate)line).Rotate(45.0);
            }
        }
     }    
}