假设我有一个Shape
对象的层次结构,每个对象都有自己的数据(折线有顶点列表,圆有中心和半径等)。
我希望能够对每个形状执行操作,例如绘制,固定到某个点,在特定点拆分为两个形状等。
一种方法是为每个操作在Shape接口中添加一个方法。然而,在这种情况下,每次添加新操作时,我都必须修改我的模型接口。我听起来不太对。我想到了以下的解决方案,想听听你的意见或其他解决方案。我将添加ShapeOperationsFactory接口和以下方法到Shape接口:
class Shape
{
public:
virtual ShapeOperationFactory* createShapeOperationsFactory() = 0;
};
class Circle : public Shape
{
public:
virtual ShapeOperationsFactory* createShapeOperationsFactor();
};
ShapeOperationsFactory* Circle::createShapeOperationsFactory()
{
return new CircleShapeOperationsFactory();
}
ShapeOperationsFactory将能够创建一组特定于形状的操作类:
class ShapeOperationsFactory
{
public:
virtual ShapeDrawer* createDrawer() = 0;
virtual ShapeSnapper* createSnapper() = 0;
virtual ShapeSplitter* createSplitter() = 0;
};
class CircleShapeOperationsFactory : public ShapeOperationsFactory
{
public:
virtual ShapeDrawer* createDrawer();
virtual ShapeSnapper* createSnapper();
virtual ShapeSplitter* createSplitter();
}
ShapeDrawer* CircleShapeOperationsFactory::createDrawer()
{
return new CircleShapeDrawer();
}
ShapeSnapper* CircleShapeOperationsFactory::createSnapper()
{
return new CircleShapeSnapper();
}
ShapeSplitter* CircleShapeOperationsFactory::createSplitter()
{
return new CircleShapeSplitter();
}
在这个实现中,当添加新操作时Shape接口不会改变。对于新的形状,我将需要实现一个新的操作工厂和每个操作类。对于新的操作,我需要为操作工厂类添加一个方法,并为每个形状添加一个实现操作的类。
通过创建Operator类使您的类更加模块化,我认为这很棒,但这并不是真正的工厂。Factory通常涉及基于某些消息(例如反序列化进程)创建对象。
对于您的情况,您可以在基类中有一个Operator成员,并在派生类的构造函数中将该成员赋值给相应的Operator派生类。
一个解决方案是使用访问者设计模式。这个设计模式的目的:
访问者设计模式是一种将算法与其操作的对象结构分离的方法。这种分离的一个实际结果是能够向现有的对象结构添加新的操作,而不修改那些结构。这是遵循开/闭原则的一种方式。
原理很简单:
创建一个访问者类:
class Visitor
{
public:
virtual void visit(Circle*) = 0;
virtual void visit(Polyline*) = 0;
...
};
将此方法添加到Shape
:
virtual void accept(class Visitor*) = 0;
然后在每个Shape
子类中实现此方法。
void Circle::accept(Visitor *v)
{
v->visit(this);
}
然后每个操作必须创建一个访问者:
class Drawer: public Visitor
{
public:
Drawer()
{
}
void visit(Circle* c)
{
drawCircle(c);
}
void visit(Polyline*p)
{
drawPolyline(p);
}
...
};
您还可以将每个访问方法委托给一个服务:(visit(Circle* c)
到CircleDrawer
)。
void visit(Circle* c)
{
circleDrawer->draw(c);
}
void visit(Polyline*p)
{
polylineDrawer->draw(p);
}
如果要添加操作,则必须创建一个新的访问者子类。
如果要添加一个形状,则必须在每个访问者上添加一个新方法。
访问者与复合设计模式(在gui编程中大量使用)协作得非常好。访问者模式可以与复合模式一起使用。对象结构可以是复合结构。在这种情况下,在复合对象的accept方法的实现中,必须调用组件对象的accept方法。
注意:我不是c++程序员,请随意编辑并使代码在语法上正确。