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

时间:2014-07-30 14:12:06

标签: c++ oop design-patterns

假设我有Shape个对象的层次结构,每个对象都有自己的数据(折线有顶点列表,圆有中心和半径等)。

我希望能够对每个形状执行操作,例如Draw,Snap到某个点,在特定点分割成两个形状等等。

一种方法是为每个操作添加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界面不会更改。对于新形状,我需要实现一个新的操作工厂和每个操作的类。对于新操作,我需要向操作工厂类添加一个方法,并为每个形状实现操作的类。

2 个答案:

答案 0 :(得分:0)

通过创建一个运算符类来使您的类更加模块化我认为很棒,但这不是一个真正的工厂。工厂通常涉及基于某些消息创建对象,例如在反序列化过程中。

对于您的情况,您可以在基类中使用Operator成员,并在派生类的构造函数中将该成员分配给相应的Operator派生类。

答案 1 :(得分:0)

解决方案可能是使用visitor design pattern。这种设计模式的目的是:

  

访问者设计模式是一种将算法与其运行的对象结构分离的方法。这种分离的实际结果是能够在不修改这些结构的情况下向现有对象结构添加新操作。这是遵循开放/封闭原则的一种方式。

原则很简单:

您创建了一个访客类:

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 ++程序员,可以自由编辑并使代码在语法上正确。