Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
我应该如何设计一组只支持某些操作的相关类? 我正在用C++编写一个基于幻灯片的应用程序。 每张幻灯片都有一个幻灯片项目集合,可以 包括标题、按钮、矩形等项目_C++_Design Patterns - Fatal编程技术网

我应该如何设计一组只支持某些操作的相关类? 我正在用C++编写一个基于幻灯片的应用程序。 每张幻灯片都有一个幻灯片项目集合,可以 包括标题、按钮、矩形等项目

我应该如何设计一组只支持某些操作的相关类? 我正在用C++编写一个基于幻灯片的应用程序。 每张幻灯片都有一个幻灯片项目集合,可以 包括标题、按钮、矩形等项目,c++,design-patterns,C++,Design Patterns,只有部分项目支持填充,而其他项目支持填充 不要 在这种情况下,实现幻灯片项目填充的最佳方法是什么? 以下是我想到的两种方法: 创建一个可填充的界面,并为幻灯片项目实现此界面 它支持填充,将所有与填充相关的属性保留在接口中。在迭代幻灯片项目列表时,dynamic_将其强制转换 进入可填充的中,如果成功,请执行与填充相关的操作 制作一个填充类。将填充指针作为幻灯片项目类的一部分,分配 fill对象,指向那些支持fill的对象的fill指针,其余对象将其保持为空。给出一个函数GetFill,该函数将返

只有部分项目支持填充,而其他项目支持填充 不要

在这种情况下,实现幻灯片项目填充的最佳方法是什么? 以下是我想到的两种方法:

  • 创建一个可填充的界面,并为幻灯片项目实现此界面 它支持填充,将所有与填充相关的属性保留在接口中。在迭代幻灯片项目列表时,dynamic_将其强制转换 进入可填充的
    中,如果成功,请执行与填充相关的操作

  • 制作一个
    填充
    类。将
    填充
    指针作为幻灯片项目类的一部分,分配
    fill
    对象,指向那些支持fill的对象的
    fill
    指针,其余对象将其保持为空。给出一个函数
    GetFill
    ,该函数将返回项目的
    fill
    (如果存在),否则返回
    NULL


  • 最好的方法是什么?我对性能和可维护性感兴趣。

    创建基类幻灯片项目:

    class SlideItem {
        public:
            virtual ~SlideItem();
            virtual void fill() = 0;
    };
    
    然后为无法填充的对象执行空实现:

    class Button : public SlideItem {
        public:
            void fill() { }
    };
    
    以及其他项目的适当填充实施:

    class Rectangle : public SlideItem {
        public:
            void fill() { /* ... fill stuff ... */ }
    };
    
    然后把它们都放在一个容器里。。如果你想填补空缺就给每个人打电话。。。易于维护。。谁在乎业绩:)


    如果您真的需要快速代码,那么您的第一个解决方案肯定是好的。但是,如果你这样做,确保你不必每次都投下它,你想填补。一次性将指针扔到一个可填充的容器中。然后,如果必须填充,则迭代此可填充容器


    再说一次,你在这方面投入了太多的精力,却没有获得合理的性能增益。(当然我不知道你的申请,这可能是合理的……但通常不是)

    我会将两者结合起来。使您的
    Fillable
    接口成为
    GetFill
    方法的返回类型。这比动态强制转换方法要好。使用dynamic cast查询接口需要实际的幻灯片项目对象实现接口(如果要支持该接口)。但是,使用诸如
    GetFill
    之类的访问器方法,您可以选择提供指向实现该接口的其他对象的引用/指针。如果接口实际上是由该对象实现的,那么也可以返回
    this
    。这种灵活性有助于避免类膨胀,并促进创建可由多个类共享的可重用组件对象

    编辑:
    这种方法也可以很好地处理空对象模式。对于不支持
    Fillable
    的对象,您可以返回一个实现该接口的简单无操作对象,而不是返回空指针。这样,您就不必担心总是检查客户机代码中的空指针了。

    看起来您要查找的内容接近实际情况。你的#2接近这种模式。下面是我要做的:

    补课。使填充指针成为幻灯片项目类的一部分,将填充对象指定为仅支持填充的对象的填充指针,其余对象将其保持为空。创建一个函数GetCapability(Capability.Fill),该函数将返回项目的填充(如果存在),否则返回NULL。如果某些对象已经实现了可填充接口,则可以将对象转换为可填充指针

    考虑存储变量项,例如
    boost::Variant

    您可以定义一个
    boost::variant
    (如果您拥有所有权,您应该使用智能指针),然后有一个要迭代的变量列表。

    答案取决于此

    如果不是每个对象都应该处理填充,那么我不认为必须用
    fill/get\u fillable\u instance/…
    来混乱基本接口有什么意义。然而,你可以仅仅通过

    struct slide_object
    {
        virtual void fill() {} // default is to do nothing
    };
    
    但这取决于您是否认为幻灯片对象抽象类中应该出现
    fill
    。但是,除非不可填充是例外情况,否则它很少应该这样做

    如果需要提供两个不同的对象类(且不超过两个),则动态强制转换是正确的,其中一些对象是可填充的,另一个与可填充性无关。在这种情况下,有两个子层次结构并在需要的地方使用动态转换是有意义的

    我在某些情况下成功地使用了这种方法,只要分派逻辑不分散(即,只有一个或两个地方可以进行动态强制转换),这种方法简单且可维护

    如果您希望有更多类似填充的行为,那么
    dynamic\u cast
    是一个错误的选择,因为它将导致

    if (auto* p = dynamic_cast<fillable*>(x))
       ...
    else if (auto* p = dynamic_cast<quxable*>(x))
       ...
    
    if(自动*p=dynamic_cast(x))
    ...
    else if(自动*p=动态_cast(x))
    ...
    

    这很糟糕。如果需要,那么实现一个访问者模式。

    我建议对形状使用一个界面,并使用一个返回填充符的方法。例如:

    class IFiller {
    public:
        virtual void Fill() = 0;
    
    protected:
        IFiller() {}
        virtual ~IFiller() {}
    };
    
    class IShape {
    public:
        virtual IFiller* GetFiller() = 0;
    
    protected:
        IShape() {}
        virtual ~IShape() {}
    };
    
    class NullFiller : public IFiller {
    public:
        void Fill() { /* Do nothing */ }
    };
    
    class Text : public IShape {
    public:
        IFiller* GetFiller() { return new NullFiller(); }
    };
    
    class Rectangle;
    class RectangleFiller : public IFiller {
    public:
        RectangleFiller(Rectangle* rectangle) { _rectangle = rectangle; }
        ~RectangleFiller() {}
    
        void Fill() { /* Fill rectangle space */ }
    
    private:
        Rectangle* _rectangle;
    };
    
    class Rectangle : IShape {
    public:
        IFiller* GetFiller() { return new RectangleFiller(this); }
    };
    

    我发现这个方法更易于维护和扩展,但不会带来主要的性能问题。

    这称为fat接口,是一种反模式。@Armen Tsirunyan:好的,对。如果有一个反模式,那么也必须有相应的模式。您当然可以向我解释:)哦,如果您的解决方案包含的类(适配器或任何东西)数量是原来的两倍,我对此不感兴趣。@duedl0r:恐怕我看错了整个段落,对不起。不幸的是,您又一次拥有了一个庞大的基类。。。这是很不幸的。你的胖班变成了变种。。。我不喜欢这种方法,尤其是如果类填充接口的数量预计会增加的话。我特别想说的是