C++ 聪明可以避免MI方法的一些问题,尽管不是全部。除此之外,它还创建了一个奇怪的继承层次结构,并增加了编译时的复杂性。一旦我们向Shape层次结构添加更多类,它也会崩溃,因为Drawable只知道如何绘制Rect 接见者模式

C++ 聪明可以避免MI方法的一些问题,尽管不是全部。除此之外,它还创建了一个奇怪的继承层次结构,并增加了编译时的复杂性。一旦我们向Shape层次结构添加更多类,它也会崩溃,因为Drawable只知道如何绘制Rect 接见者模式,c++,inheritance,multiple-inheritance,crtp,C++,Inheritance,Multiple Inheritance,Crtp,允许我们将遍历对象层次与操作对象层次的算法分离。因为每个对象都知道自己的类型,所以即使不知道算法是什么,它也可以调度适当的算法。使用Shape、Circle和Rect进行说明: class Shape { public: virtual void accept(class Visitor &v) = 0; }; class Rect : public Shape { public: float width; float heig

允许我们将遍历对象层次与操作对象层次的算法分离。因为每个对象都知道自己的类型,所以即使不知道算法是什么,它也可以调度适当的算法。使用
Shape
Circle
Rect
进行说明:

class Shape
{
    public:
        virtual void accept(class Visitor &v) = 0;
};

class Rect : public Shape
{
   public:
       float width;
       float height;

       void accept(class Visitor &v)
       {
           v.visit(this);
       }
};

class Circle : public Shape
{
    public:
        float radius;

       void accept(class Visitor &v)
       {
           v.visit(this);
       }
};

class Visitor
{
    public:
        virtual void visit(Rect *e) = 0;
        virtual void visit(Circle *e) = 0;
};

class ShapePainter : public Visitor
{
    // Provide graphics-related implementations for the two methods.
};

class ShapeSerializer : public Visitor
{
    // Provide methods to serialize each shape.
};
通过这样做,我们牺牲了一些运行时复杂性,但将我们的各种关注点与数据解耦。现在在程序中添加新的关注点很容易。我们所需要做的就是添加另一个
Visitor
类来完成我们想要的任务,并将
Shape::accept()
与这个新类的对象结合使用,如下所示:

class ShapeResizer : public Visitor
{
    // Resize Rect.
    // Resize Circle.
};

Shape *shapey = new Circle();
ShapeResizer sr;
shapey->accept(sr);
这种设计模式还有一个优点,即如果您忘记实现某些数据/算法组合,但在程序中使用它,编译器会抱怨。我们可能希望稍后重写
Shape::accept()
,以定义(比如)聚合形状类型,如
ShapeStack
。这样我们可以遍历并绘制整个堆栈


我认为,如果性能在您的项目中不是至关重要的,那么访问者解决方案就更优越。如果您需要满足实时约束条件,但这不会降低程序的速度,从而影响到最后期限的完成,那么也可能值得考虑。

然后,您应该发展您的想法:TS可以提供启用的
和禁用的
策略实施。缺点是这套政策总是固定不变的。谢谢你给出了一个非常有见地的答案。我会考虑访客模式。但我想知道最终用户的语法是什么?使用Crtp模式,我可以使用Box->addChild(Box*)、Box->serialize()等。如果您有兴趣为最终用户提供一个更简单的界面(例如,如果您的代码是一个库),您可以创建一个外观类似于
形状的外观对象(
Rect
Box
Circle
等)但知道在调用
Box->serialize()
时如何在全局
序列化程序
对象上使用Visitor。通过这种方式,您不会使MI变得复杂,但仍然可以在库中保持灵活性,同时为用户提供易于使用的界面。希望能有帮助,我明白了。当我不知道我的盒子将启用哪些功能时,我仍然不清楚如何构建这个facade对象?我不能为每一个可能的变体构建一个facade。不,你不能为每一个可能的组合构建一个facade对象,你也不应该。但是,您应该决定是否要向最终用户隐藏复杂性,并提供一个简单的界面,或者让用户能够访问库的全部功能和复杂性。事实上,您可以使用CRTP来获得您想要的语法类型,但是它带来了我已经提到的许多问题。如果你问我,我会设计一个简单的通用案例,同时仍然允许在需要做一些不同的事情时访问更复杂的内部结构。
class Rect{
    public:
       float width;
       float height;
}

template <class RectType>
class Stackable{
    public:
        void addChild(RectType* c){
             children.push_back(c);
        }
        std::vector<RectType*> children;
}

template <class RectType>
class Drawable{
    public:
        virtual void draw(){
            RectType* r static_cast<RectType>(this);
            drawRect(r->width, r->height);
        }
}

template <class RectType>
class Styleable{
    public:
        int r, g, b;
}

class CustomRect: public Rect, public Stackable<CustomRect>, public Drawable<CustomRect>{
}

class CustomRectWithStyle: public Rect, public Stackable<CustomRect>, public Drawable<CustomRect>, public Styleable<CustomRect>{
    public:
}
#define FEATURED(FEATURE, VALUE) \
template <template<class>class Feature = FEATURE> \
typename std::enable_if<std::is_base_of<Feature<RectType>, RectType>::value == VALUE>::type

template <class RectType>
class Styleable;

template <class RectType>
class Drawable{
    public:

        FEATURED(Styleable, true)
        drawImpl()
        {
            std::cout << "styleable impl\n";
        }

        FEATURED(Styleable, false)
        drawImpl()
        {
            std::cout << "not styleable impl\n";
        }


        virtual void draw(){
            drawImpl();
        }
};
class Shape
{
    public:
        virtual void accept(class Visitor &v) = 0;
};

class Rect : public Shape
{
   public:
       float width;
       float height;

       void accept(class Visitor &v)
       {
           v.visit(this);
       }
};

class Circle : public Shape
{
    public:
        float radius;

       void accept(class Visitor &v)
       {
           v.visit(this);
       }
};

class Visitor
{
    public:
        virtual void visit(Rect *e) = 0;
        virtual void visit(Circle *e) = 0;
};

class ShapePainter : public Visitor
{
    // Provide graphics-related implementations for the two methods.
};

class ShapeSerializer : public Visitor
{
    // Provide methods to serialize each shape.
};
class ShapeResizer : public Visitor
{
    // Resize Rect.
    // Resize Circle.
};

Shape *shapey = new Circle();
ShapeResizer sr;
shapey->accept(sr);