首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在模型上添加操作而不向模型添加代码

问在模型上添加操作而不向模型添加代码
EN

Stack Overflow用户
提问于 2014-07-30 14:12:06
回答 2查看 88关注 0票数 2

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

我想要能够对每个形状执行操作,如绘制,在某个点上折断,在一个特定点分裂成两个形状,等等。

一种方法是为每个操作添加一个方法来构造接口。但是,在这种情况下,每次添加新操作时,我都必须修改我的模型接口。我听起来不对。我想出了以下解决方案,并希望在此提出您的意见或其他解决方案。

我将添加一个ShapeOperationsFactory接口和下面的方法来塑造接口:

代码语言:javascript
复制
class Shape
{
public:
    virtual ShapeOperationFactory* createShapeOperationsFactory() = 0;
};

class Circle : public Shape
{
public:
    virtual ShapeOperationsFactory* createShapeOperationsFactor();
};

ShapeOperationsFactory* Circle::createShapeOperationsFactory()
{
    return new CircleShapeOperationsFactory();
}

ShapeOperationsFactory将能够创建一组特定于形状的操作类:

代码语言:javascript
复制
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();
}

在此实现中,当添加新操作时,形状接口不会更改。对于新的形状,我将需要实现一个新的操作工厂和一个类的每个操作。对于新的操作,我需要向操作工厂类添加一个方法,并为每个形状添加一个实现操作的类。

EN

回答 2

Stack Overflow用户

发布于 2014-07-30 14:52:38

通过创建操作符类使类更加模块化,我认为这是很棒的,但这并不是真正的工厂。工厂通常涉及创建基于某些消息的对象,例如在非序列化过程上。

对于您的情况,您可以在基类和派生类的构造函数中有一个运算符成员,您可以将该成员分配给适当的运算符派生类。

票数 0
EN

Stack Overflow用户

发布于 2014-07-30 15:16:36

解决方案可以是使用游客设计模式。这种设计模式的目的是:

访问者设计模式是将算法从其操作的对象结构中分离出来的一种方法。这种分离的一个实际结果是能够在现有对象结构中添加新的操作,而无需修改这些结构。这是遵循开放/封闭原则的一种方式。

原则很简单:

您可以创建一个访问者类:

代码语言:javascript
复制
class Visitor
{
  public:
    virtual void visit(Circle*) = 0;
    virtual void visit(Polyline*) = 0;
    ...
};

将此方法添加到Shape中

代码语言:javascript
复制
virtual void accept(class Visitor*) = 0;

然后在每个Shape子类中实现此方法。

代码语言:javascript
复制
void Circle::accept(Visitor *v)
{
    v->visit(this);
}

然后您必须在每个操作中创建一个访问者:

代码语言:javascript
复制
class Drawer: public Visitor
{
  public:
    Drawer()
    {
    }
    void visit(Circle* c)
    {
        drawCircle(c);
    }
    void visit(Polyline*p)
    {
        drawPolyline(p);
    }
    ...
};

还可以将每个访问方法委托给一个服务:(visit(Circle* c)到一个CircleDrawer)。

代码语言:javascript
复制
    void visit(Circle* c)
    {
        circleDrawer->draw(c);
    }
    void visit(Polyline*p)
    {
        polylineDrawer->draw(p);
    }

如果要添加操作,则必须创建一个新的访问者子类。

如果要添加形状,则必须对每个访问者添加一个新方法。

访问者与复合设计模式的协作非常好(在gui编程中大量使用)。访问者模式可以与复合模式一起使用。对象结构可以是复合结构。在这种情况下,在复合对象的accept方法的实现中,必须调用组件对象的accept方法。

注意:我不是一个c++程序员,随时可以编辑和使代码语法正确。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25039088

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档