C# 从派生类更改基类的正确方法
我正在尝试设计几个基本的绘图类,从中可以继承和定义复杂的绘图C# 从派生类更改基类的正确方法,c#,inheritance,design-patterns,C#,Inheritance,Design Patterns,我正在尝试设计几个基本的绘图类,从中可以继承和定义复杂的绘图 public abstract class Drawing { public bool CanBeRotated { get; set; } private float m_rotation; public float Rotation { get { return m_rotati
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);
}
}
如您所见,LineDrawing
和CompoundDrawing
派生自抽象绘图类。CompoundDrawing
有一个内部的列表
,允许我们存储所需数量的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);
}
}
公共抽象类绘图
{
公共布尔堪培拉酒店
{
得到;
设置
}
私人浮动m_旋转;
公众浮标轮换
{
得到
{
返回m_旋转;
}
}
受保护的图形()
{
堪培拉=真;
}
公共空心旋转(浮动度)
{
如果(堪培拉)
m_旋转=度;
}
}
公共密封类线条图:图形
{
专用只读线路m_线;
公用线路
{
得到
{
返回m_线;
}
}
公共线条图(线条)
{
m_线=线;
}
}
公共类复合绘图:绘图
{
受保护的IList m_图纸;
受保护的复合图纸(ILST图纸)
{
m_图纸=新列表(图纸);
}
}
假设我想定义一个从CompoundDrawing派生的矩形图形
public class RectangleDrawing : CompoundDrawing
{
public RectangleDrawing(IList<LineDrawing> lineDrawings) : base(lineDrawings)
{
foreach(var line in lineDrawings)
{
line.CanBeRotated = false;
}
}
}
公共类矩形绘图:复合绘图
{
公共矩形图形(IList线条图形):基础(线条图形)
{
foreach(线条图中的var线条)
{
line.CanBeRotated=false;
}
}
}
现在我面临一个问题!显然,我不希望这个新类中的线条绘制对象是可旋转的!但我不确定在这个模式中我应该设置在哪里我会考虑采取一种不可改变的方法:
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)));
protected override图形旋转(浮动degeee)
//注意,我传递的是IEnumerable而不是IList
//为什么需要一个IList,而不是让API承担不必要的负担
//限制。
=>newrectange(lines.Select(l=>l.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);
}
}
}
}
公共接口IRotate
{
空隙旋转(浮动度);
}
公共类方形绘图:绘图,旋转
{
公共空心旋转(浮动度)
{
//旋转图形的实际代码
}
}
公共类矩形绘图:复合绘图
{
公共矩形图形(IList线条图形):基础(线条图形)
{
foreach(线条图中的var线条)
{
如果(线是旋转的)
{
((旋转)线)。旋转(45.0);
}
}
}
}
所以你不想旋转矩形绘图
或组成线段?@BradleyDotNET线段!我想您只需要对lineDrawings
进行一次处理,然后设置它们的CanBeRotated
属性。或者更改您的继承模型,使每个类始终是可旋转的或不可旋转的。那又怎样?你还在写这门课。如果您的基本问题是“派生类能否接触基类成员”,那么答案是响亮的“是”。您仍然需要旋转线条才能旋转矩形。如果将属性设置为false
,则在旋转矩形时需要将其临时重置为true
。我认为你的整个计划太复杂了,它对你不利,而不是帮助你。