超越开放原则

我有一个简单的程序,它根据用户提供的鼠标数据绘制几何图形。 我有一个处理鼠标跟踪的类(它获取带有鼠标移动历史的List)和一个名为Shape的抽象类。 在这个类中,我对一些额外的形状进行了简化,比如Circle,Rectangle等 – 并且它们中的每一个都会覆盖抽象的Draw()函数。

这一切都运行良好,但问题来自我希望用户能够手动切换所需的形状。 我得到了鼠标数据,我知道应该绘制什么样的形状。 问题是如何使代码“知道”它应该创建哪个对象并将适当的参数传递给构造函数。 此时也不可能添加新的Shape衍生物,这是完全错误的。

我好像不想出来像这样的代码:

List Shapes = new List(); // somwhere later if(CurrentShape == "polyline"){ Shapes.Add(new Polyline(Points)); } else if (CurrentShape == "rectangle"){ Shapes.Add(new Rectangle(BeginPoint, EndPoint)); } // and so on. 

上面的代码清楚地certificate了开放 – 封闭原则。 问题是我没有任何好主意如何克服它。 主要问题是不同的Shapes具有不同参数的构造函数,这使得它更加麻烦。

我很确定这是一个常见的问题,但我不知道如何克服它。 你有什么想法吗?

它乞求工厂,但不仅仅是工厂,而是工厂与注射工人。

 public class Context { public Point BeginPoint; public Point EndPoint; public List Points; whatever else } public class ShapeFactory { List workers; public Shape CreateShape( string ShapeName, Context context ) { foreach ( FactoryWorker worker in workers ) if ( worker.Accepts( ShapeName ) ) return worker.CreateShape( context ); } public void AddWorker( FactoryWorker worker ) { workers.Add( worker ); } } public abstract class FactortWorker { public abstract bool Accepts( string ShapeName ); puboic Shape CreateShape( Context context ); } public class PolyLineFactoryWorker : FactoryWorker { public override bool Accepts( string ShapeName ) { return ShapeName == "polyline"; } public Shape CreateShape( Context context ) { ... } } 

通过这种方式,代码可以进行扩展 – 可以自由创建新的工厂工人并将其添加到工厂中。

当您需要创建所有派生自单个类或实现相同接口的对象时,一种常见的方法是使用工厂 。 但是,在您的情况下,简单的工厂可能还不够,因为工厂本身需要是可扩展的。

实现它的一种方法如下:

 interface IShapeMaker { IShape Make(IList points); } class RectMaker : IShapeMaker { public Make(IList points) { // Check if the points are good to make a rectangle ... if (pointsAreGoodForRectangle) { return new Rectangle(...); } return null; // Cannot make a rectangle } } class PolylineMaker : IShapeMaker { public Make(IList points) { // Check if the points are good to make a polyline ... if (pointsAreGoodForPolyline) { return new Polyline(...); } return null; // Cannot make a polyline } } 

有了这些Maker类,你可以让制造商的注册表(一个简单的List )通过制造商传递它们的点数,并在你获得非空形状时停止。

该系统仍然是可扩展的,因为您可以添加一对NewShapeNewShapeMaker ,并将其“插入”到现有框架中:一旦NewShapeMaker进入注册表,系统的其余部分立即就可以识别并使用您的NewShape