在Model上添加操作而不向Model中添加代码



假设我有一个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++程序员,请随意编辑并使代码在语法上正确。

最新更新