• 设计模式-Note8-数据结构类


    Composite

    组合模式

    将对象组成树形结构以表示“部分-整体”的层次结构。Composite使得用户对单个对象和组和对象的使用具有一致性(稳定)。

    解决什么问题

    软件在某些情况下,客户代码过多地依赖于对象容器负载的内部实现结构,对象容器内部实现结构(而非抽象接口)的变化将引起客户代码(invoke函数)的频繁变化,带来了代码的维护性、扩展性等弊端。

    如何将“客户代码与复杂对象容器结构”解耦?让对象容器自己来实现自身的复杂结构,从而使得客户代码就像处理简单对象一样来处理复杂的对象容器。

    结构

    要点总结

    1. Composite模式采用树形结构来实现普遍存在的对象容器,从而将“一对多”的关系转化为“一对一”的关系,使得客户代码可以一致地(复用)处理对象和对象容器,无需关心处理的是单个的对象,还是组合的对象容器。
    2. 将“客户代码与复杂的对象容器结构”解耦是Composite的核心思想,解耦之后,客户代码将与纯粹的抽象接口——而非对象容器的内部实现结构——发生依赖,从而更能“应对变化”。
    3. Composite模式在具体实现中,可以让父对象中的子对象反向追溯;如果父对象有频繁的遍历需求,可以使用缓存技巧来改善效率。

    示例

    class Component {
    public:
        virtual void process() = 0;
        virtual ~Component() {}
    };
    
    class Composite : public Component {
    private:
        string name;
        list<Component*> elements;
    public:
        Composite(const string& s) : name(s) {}
        void add(Component* element) {
            elements.push_back(element);
        }
        void remove(Component* element) {
            elements.remove(element);
        }
    
        void process() {
            // process current node
    
            // process leaf nodes
            for (auto &e : elements) {
                e->process();
            }
        }
    };
    
    class Leaf : public Component {
    private:
        string name;
    public:
        Leaf(string s) : name(s) {}
    
        void process() {
            // process current node
        }
    };
    
    // 稳定
    void Invoke(Component& element) {
        // ... 
        element.process();
    }
    
    int main() {
        Composite root("root");
        Composite treeNode1("treeNode1");
        Composite treeNode2("treeNode2");
        Composite treeNode3("treeNode3");
        Composite treeNode4("treeNode4");
        Leaf left1("left1");
        Leaf left2("left2");
    
        root.add(&treeNode1);
        treeNode1.add(&treeNode2);
        treeNode2.add(&left1);
    
        root.add(&treeNode3);
        treeNode3.add(&treeNode4);
        treeNode4.add(&left2);
    
        process(root);
    }
    

    Iterator

    迭代器

    提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露(稳定)该对象的内部表示。

    解决什么问题

    在软件构建过程中,集合对象内部结构常常变化各异。但对于这些集合对象,我们希望不暴露其内部结构的同时,可以让外部客户嗲吗透明地访问其中包含的元素;同时这种“透明遍历”也为“同一种算法在多种集合对象上进行操作”提供了可能。

    使用面向对象的技术将这种遍历机制抽象为“迭代器对象”为“应对变化中的集合对象”提供了一种优雅的方式。

    结构

    要点总结

    1. 迭代抽象:访问一个聚合对象的内容而无需暴露它的内部表示。
    2. 迭代多态:为遍历不同的集合结构提供一个统一的接口,从而支持同样的算法在不同集合结构上进行操作。
    3. 迭代器的健壮性考虑:遍历的同时更改迭代器所在的集合结构,会导致问题。

    示例

    template<typename T>
    class Iterator {
    public:
        virtual void first() = 0;
        virtual void next() = 0;
        virtual bool isDone() const = 0;
        virtual T& current() = 0;
    };
    
    template<typename T>
    class MyCollection {
    public:
        Iterator<T> GetIterator() {
            // ... 
        }
    
    };
    
    template<typename T>
    class CollectionIterator : public Iterator<T> {
    private:
        MyCollection<T> mc;
    public:
        CollectionIterator(const MyCollection<T>& c) : mc(c) { }
    
        void first() override {
    
        }
        void next() override {
    
        }
        bool isDone() const override {
    
        }
        T& current() override {
    
        }
    }
    
    void MyAlgorithm() {
        MyCollection<int> mc;
    
        Iterator<int> iter = mc.GetIterator();
    
        for (iter.first(); !iter.isDone(); iter.next()) {
            // ...
        }
    }
    

    Chain of Resposibility

    职责链

    使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。

    解决什么问题

    在软件构建过程中,一个请求可能被多个对象处理,但是每个请求在运行时只能有一个接受者,如果显示指定,将必不可少地带来请求发送者与接受着的紧耦合。

    如何使请求的发送者不需要指定具体的接受者?让请求的接受者自己在运行时决定来处理请求,从而使两者解耦。

    结构

    要点总结

    1. Chain of Responsibility 模式的应用场合在于“一个请求可能有多个接受者,但最后真正的接受者只有一个”,这时候请求发送者与接受者的耦合有可能出现“变化脆弱”的症状,职责链的目的就是将二者解耦,从而更好地应对变化。
    2. 应用了Chain of Responsibility模式后,对象的职责分派将更具灵活性。我们可以在运行时动态添加/修改请求的处理职责。
    3. 如果请求传递到职责链的末尾仍得不到处理,应该有一个合理的缺省机制。这也是每一个接受对象的责任,而不是发出请求的对象的责任。

    示例

    class Request {
    private:
        string description;
        RequestType reqType;
    public:
        Request(const string& desc, RequestType type) : description(desc), reqType(type) {}
        RequestType getReqType() const { return reqType; }
        const string& getDescription() const { return description; }
    };
    
    class ChainHandler {
    private:
        ChainHandler* nextChain;
        void sendRequestToNextHandler(const Request& req) {
            if (nextChain != nullptr) {
                nextChain->handle(req);
            }
        }
    protected:
        virtual bool canHandleRequest(const Request& req) = 0;
        virtual void processRequest(const Request& req) = 0;
    public:
        virtual ~ChainHandler() {}
        ChainHandler() {
            nextChain = nullptr;
        }
        void setNextChain(ChainHandler* next) {
            nextChain = next;
        }
        void handle(const Request& req) {
            if (canHandleRequest(req)) {
                processRequest(req);
            }
            else {
                sendRequestToNextHandler(req);
            }
        }
    };
    
    class Handler1 : public ChainHandler {
    protected:
        bool canHandleRequest(const Request& req) override {
            return req.getReqType() == RequestType::REQ_HANDLER1;
        }
        void processRequest(const Request& req) override {
            // ... 
        }
    };
    
    class Handler2 : public ChainHandler {
    protected:
        bool canHandleRequest(const Request& req) override {
            return req.getReqType() == RequestType::REQ_HANDLER2;
        }
        void processRequest(const Request& req) override {
            // ... 
        }
    };
    
    class Handler3 : public ChainHandler {
    protected:
        bool canHandleRequest(const Request& req) override {
            return req.getReqType() == RequestType::REQ_HANDLER3;
        }
        void processRequest(const Request& req) override {
            // ... 
        }
    };
    
    int main() {
        Handler1 h1;
        Handler2 h2;
        Handler3 h3;
    
        h1.setNextChain(&h2);
        h2.setNextChain(&h3);
    
        Request request("process task ...", RequestType::REQ_HANDLER3);
        h1.handle(request);
        return 0;
    }
    
    转载请注明出处
  • 相关阅读:
    vue中webpack和less填坑:项目运行起来报错TypeError: this.getOptions is not a function
    js避坑历险记
    npm -S -D -g i 有什么区别
    Java 中无返回值的方法在使用时应该注意的问题
    java中方法的重载和覆盖
    Java中的内存划分
    git常用操作
    java代码书写易犯错误
    Java基础知识了解
    粘性定位position:sticky
  • 原文地址:https://www.cnblogs.com/lnlin/p/15343278.html
Copyright © 2020-2023  润新知