• 设计模式 笔记 组合模式 Composite





    //---------------------------15/04/16----------------------------


    //Composite 组合模式----对象结构型模式



    /*

        1:意图

            将对象组合成树形结构以表示部分-整体的层次结构。Composite使得用户对单个对象和

            组合对象的使用具有一致性。

        2:动机:

        3:适用性:

            1>你想表示对象的部分-整体层次结构。

            2>你希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。

        4:结构:

            Client--------->Component:<--------------

                            Operation()             |

                            Add(Component)          |

                            Remove(Component)       |

                            GetChild(int)           |

                                |                   |

                                |                   |

                          --------------            |

                          |             |           |

                        Leaf:       Composite:      |

                        Operation() children---------

                                    Operation()

                                    { for all g in children

                                        { g.Operation()}

                                    }

                                    Add(Comonent)

                                    Remove(Component)

                                    GetChild(int)

        5:参与者:

            1>Component

                1)为组合中的对象声明接口。

                2)在适当的情况下,实现所有类共有接口的缺省行为。

                3)声明一个接口用于访问和管理Component的子组件。

                4)(可选)在递归结构中定义一个接口,用于访问一个父部件,并在合适的情况下实现它。

            2>Leaf

                1)在组合中表示叶节点对象,叶节点没有子节点。

                2)在组合中定义图元对象的行为。

            3>Composite

                1)定义有子部件的那些部件的行为。

                2)存储子部件。

                3)Component接口中实现与子部件有关的操作。

            4>Client

                通过Component接口操纵组合部件的对象。

        6:协作:

            用户使用Component类接口与组合结构中的对象进行交互。如果接收者是一个叶节点,则直接处理请求。

            如果接受者是Composite,它通常将请求发送给它的子部件,在转发请求之前与()之后可能执行一些

            辅助操作。

        7:效果:

            1>定义了包含基本对象和组合对象的类层次结构。

                基本对象可以被组合成更复杂的组合对象,而这个组合对象又可以被组合,这样不断递归下去。客户

                代码中,任何用到基本对象的地方都可以使用组合对象。

            2>简化客户代码。

                客户可以一致地使用组合结构和单个对象。通常用户不知道(也不关心)处理的是一个叶节点还是一个

                组合对象。这样就简化了客户代码,不必写一大堆选择语句来区分它们。

            3>使得更容易增加新类型的组件。

                新定义的CompositeLeaf子类自动地与已有的结构和客户代码一起工作,客户程序不需因新增

                Component类而改变。

            4>使你的设计变得更加一般化。

                容易增加新组件意味着很难限制组合中的组件。如果你希望一个组合只能由一些特定的组件,

                在使用Composite模式时却不能依赖类型系统施加这些约束,而必须在运行时刻进行检查。

        8:实现:

            1>显示的父部件引用。(也就是存储一个父节点的指针)

                保持从子部件到父部件的引用能简化组合结构的遍历和管理。父部件引用可以简化结构的上移和

                组件的删除,同时也能支持责任链模式。

                对于父部件引用必须维护一个不变式,即一个组合的所有子节点以这个组合为父节点,而反之

                该组合以这些节点为子节点。可以选择在Composite类的AddRemove操作中实现这种方法。

            2>共享组件:

                共享组件可以减少对存储的需求,可以使用Flywight方式来实行共享。

            3>最大化Component接口

                Composite模式的目的之一是使得用户不知道他们正在使用的具体的LeafComposite类。

                为了达到这个目的,Component类应该为LeafComposite类尽可能多定义一些公共操作。

                为了不限制Leaf类,可以对Composite类才需要的 操作实现缺省的操作。

            4>声明管理子部件的操作

                选择在Component类还是在Composite类中声明管理子部件的操作,这需要在安全性和透明性之间

                做出选择:

                1)Component中声明:这样拥有良好的透明性,因为这样可以一致地使用所有组件,但是会付出

                  安全性的代价,因为客户有可能会在Leaf中做出无意义的操作,比如增加或删除对象。

                2)Composite类中声明:这样做女友良好的安全性,但损失了透明性。接口变得不一致了。

                这里我们比较看重透明性:所以要在Component中定义缺省的AddRemove操作。这时又带来一个问题

                客户可能会向一个Leaf中添加或删除组件,所以通常可以使用缺省方式处理AddRemove的失败。

                有一个方式是:产生一个异常,这样客户就能知道失败原因了。

            5>Component是否应该实现一个Component列表。

                也就是在Component中是否应该存放子节点的指针,这个答案是只有在叶子节点相对很少时才值得

                这么做,因为叶子节点没有子节点,存放指针会浪费空间。

            6>子部件排序。

                如果需要考虑子节点的顺序时,必须仔细地设计对子节点的访问和管理接口,以便管理子节点序列。

                可以参考iterator模式。

            7>使用高速缓存改善性能。

                使用缓存机制可以加速对子部件的访问。但是如果子部件发生了变化,那么这个子部件必须通知他的

                父节点高速缓存失效了。所以需要在Compnent中定义一个private接口。

            8>应该由谁删除Component

                通常最好由Composite负责删除其子节点。Leaf对象不会改变,所以可以被共享而不删除。

            9>存贮组件最好用哪一种数据结构

                什么效率高就用什么,包括数组,树,hash表,链表。

        9:代码示例:                                                                         */


    //假设我们要组装一台电脑,这里每个设备只需要知道其价格就行,所以可以设计一个component

    //Compnent类: 给出了设备名 和价格 以及对子部件的操作

    class Equipment

    {

    public:

        virtual ~Equipment();

        

        const char* Name() { return _name;}

        virtual Watt Power();

        virtual Currency NetPrice();

        virtual Currency DiscountPrice();

        

        virtual void Add(Equipment*);

        virtual void Remove(Equipment*);

        virtual Iterator<Equipment*>* CreateIterator();

        

    protected:

        Equipment(const char*);

        

    private:

        const char* _name;

    };


    //Leaf组件:实现了Compnent类中的组件特有操作

    class FloppyDisk : public Equipment

    {

    public:

        FloppyDisk(const char*);

        virtual ~FloppyDisk();

        

        virtual Watt Power();

        virtual Currency NetPrice();

        virtual Currency DiscountPrice();

    };


    //Composite类:实现了对子部件的操作

    class CompositeEquipment : public Equipment

    {

    public:

        virtual ~CompositeEquipment();

        

        virtual Watt Power();

        virtual Currency NetPrice();

        virtual Currency DiscountPrice();

        

        virtual void Add(Equipment*);

        virtual void Remove(Equipment*);

        virtual Iterator<Equipment*>* CreateIterator();

        

    protected:

        CompositeEquipment(const char*);


    private:

        List<Equipment*> _equipment;

    };


    //具体的实现,统计每个子部件的价格

    Currency CompositeEquipment::NetPrice()

    {

        Iterator<Equipment*>* i = CreateIterator();

        Currency total = 0;

        

        for(i->First(); !i->IsDone(); i->Next())

        {

            total += i->CurrentItem()->NetPrice();

        }

        delete i;

        return total;

    }


    //具体的Composite类,主板

    class Chassis : public CompositeEquipment

    {

    public:

        Chassis(const char*);

        virtual ~Chassis();

        

        virtual Watt Power();

        virtual Currency NetPrice();

        virtual Currency DiscountPrice();

    };


    //机箱

    Cabinet* cabinet = new Cabinet("PC Cabinet");


    Chassis* chassis = new Chassis("PC Chassis");


    cabinet->Add(chassis);

    //适配卡bus

    Bus* bus = new Bus("MCA Bus");

    //加了张网卡

    bus->Add(new Card("16Mbs Token Ring"));


    chassis->Add(bus);

    //加了张软盘

    chassis->Add(new FloppyDisk("3.5in Floppy"));


    cout<<"Thee net Price is"<<chassis->NetPrice()<<endl;





  • 相关阅读:
    二战后的一些战争启示(弱国无外交)
    为了生存人类必须去探索宇宙
    不同版本Eclipse对JDK版本要求
    string 转 java对象、转map的方式
    原生JS实现全选,反选
    oracle批量update
    HttpURLConnection 当作请求调用接口不带返回参数的工具类
    sun.misc.BASE64Encoder在Eclipse中不能直接使用的原因和解决方案
    javamail 发送邮件demo(文字与附件)
    Linux ping不通百度的解决方法
  • 原文地址:https://www.cnblogs.com/boydfd/p/4983133.html
Copyright © 2020-2023  润新知