我有一个画图演示程序:在不同的表面上画不同的形状。
----------------------------------------------------------
表面:Surface(表面)、EtchASketch(浮雕表面)
形状:Shape(形状)、Ploygon(多边形)、Quadrilateral(四边形)、Parallelogram(平行四边形)、Rectangle(矩形)
----------------------------------------------------------
下面的代码,显然违反了OCP原则:
如果要添加一个新Surface的话,我必须要在所有的Shape里添加新方法!
我想请高手们看看,应该如何重构这段程序,以及说说为什么?
非常感谢!
class Surface
{
public virtual void Draw(Shape shape)
{
shape.Draw(this);
}
}
class EtchASketch : Surface
{
public override void Draw(Shape shape)
{
shape.Draw(this);
}
}
class Shape
{
public virtual void Draw(Surface surface)
{
Console.WriteLine("A shape is drawn on the surface with ink.");
}
public virtual void Draw(EtchASketch etchASketch)
{
Console.WriteLine("The knobs are moved in attempt to draw the shape.");
}
}
class Polygon : Shape
{
public override void Draw(Surface surface)
{
Console.WriteLine("A polygon is drawn on the surface with ink.");
}
public override void Draw(EtchASketch etchASketch)
{
Console.WriteLine("The knobs are moved in attempt to draw the polygon.");
}
}
class Quadrilateral : Polygon
{
public override void Draw(Surface surface)
{
Console.WriteLine("A quadrilateral is drawn on the surface with ink.");
}
public override void Draw(EtchASketch etchASketch)
{
Console.WriteLine("The knobs are moved in attempt to draw the quadrilateral.");
}
}
class Parallelogram : Quadrilateral
{
public override void Draw(Surface surface)
{
Console.WriteLine("A parallelogram is drawn on the surface with ink.");
}
public override void Draw(EtchASketch etchASketch)
{
Console.WriteLine("The knobs are moved in attempt to draw the parallelogram.");
}
}
class Rectangle : Parallelogram
{
public override void Draw(Surface surface)
{
Console.WriteLine("A rectangle is drawn on the surface with ink.");
}
public override void Draw(EtchASketch etchASketch)
{
Console.WriteLine("The knobs are moved in attempt to draw the rectangle.");
}
}
class Program
{
static void Main(string[] args)
{
Surface surface = new Surface();
Surface etchASketch = new EtchASketch();
var shapes = new List<Shape>
{
new Shape(),
new Polygon(),
new Quadrilateral(),
new Parallelogram(),
new Rectangle()
};
foreach (Shape shape in shapes)
{
surface.Draw(shape);
etchASketch.Draw(shape);
}
Console.ReadLine();
}
}
有什么样的表面是形状的一种属性,一般情况下一种形状对应一种表面,所以表面是形状的属性,在实例化中指定,不知道我这样说有没有明白。
关键还是回归到需求。
现在的情况是一组表面+形状,需要一个绘图实现,不管你将代码放在表面,还是形状,结果都是不可避免要添加“乘数级别”的新实现。 比如 m * n 你m+1 你要实现n个新实现。 n+1你要实现m个新实现。
但是你却想增加一个子类,也就是增加一个实现,就解决问题,这是不可能的。
这种情况,也许根本就不应该分成两个类。