• 设计模式


    设计模式 Design Patterns

    学习资料

    创建型模式

    创建型模式提供了创建对象的机制, 能够提升已有代码的灵活性和可复用性。

    单例模式 Singleton

    Singleton is a creational design pattern that lets you ensure that
    a class has only one instance,
    while providing a global access point to this instance.

    1. 默认构造函数私有化
    2. 新建一个静态构建方法作为构造函数
    /**
     * The Singleton class defines the `GetInstance` method that serves as an
     * alternative to constructor and lets clients access the same instance of this
     * class over and over.
     */
    class Singleton
    {
    
        /**
         * The Singleton's constructor/destructor should always be private to
         * prevent direct construction/desctruction calls with the `new`/`delete`
         * operator.
         */
    private:
        static Singleton * pinstance_;
        static std::mutex mutex_;
    
    protected:
        Singleton(const std::string value): value_(value)
        {
        }
        ~Singleton() {}
        std::string value_;
    
    public:
        /**
         * Singletons should not be cloneable.
         */
        Singleton(Singleton &other) = delete;
        /**
         * Singletons should not be assignable.
         */
        void operator=(const Singleton &) = delete;
        /**
         * This is the static method that controls the access to the singleton
         * instance. On the first run, it creates a singleton object and places it
         * into the static field. On subsequent runs, it returns the client existing
         * object stored in the static field.
         */
    
        static Singleton *GetInstance(const std::string& value);
        /**
         * Finally, any singleton should define some business logic, which can be
         * executed on its instance.
         */
        void SomeBusinessLogic()
        {
            // ...
        }
        
        std::string value() const{
            return value_;
        } 
    };
    
    /**
     * Static methods should be defined outside the class.
     */
    
    Singleton* Singleton::pinstance_{nullptr};
    std::mutex Singleton::mutex_;
    
    /**
     * The first time we call GetInstance we will lock the storage location
     *      and then we make sure again that the variable is null and then we
     *      set the value. RU:
     */
    Singleton *Singleton::GetInstance(const std::string& value)
    {
        std::lock_guard<std::mutex> lock(mutex_);
        if (pinstance_ == nullptr)
        {
            pinstance_ = new Singleton(value);
        }
        return pinstance_;
    }
    

    工厂模式

    1. 简单工厂模式:
      单工厂,生产各种产品
      弊端:
    1. 产品过多时导致工厂过于庞大,变成超级类
    2. 要生产新的产品就要向工厂添加分支
    1. 工厂方法模式:
      每个产品有单独的工厂
      优点:要生产新的产品添加新的工厂即可
    2. 抽象工厂模式:
      在工厂方法模式上提取出工厂接口,各个产品工厂都实现该工厂接口

    生成器模式

    适用场景:
    · 相同的方法,不同的执行顺序,产生不同的结果。
    · 多个部件或零件,都可以装配到一个对象中,但是产生的结果又不相同。
    · 产品类非常复杂,或者产品类中不同的调用顺序产生不同的作用。
    · 初始化一个对象特别复杂,参数多,而且很多参数都具有默认值。

    原型模式

    重写拷贝函数

    结构模式

    把类或对象结合在一起形成一个更大的结构。一般是解决不同的类之间有不同关系的情况。

    适配器模式

    包含角色有目标接口,适配者类,适配器类
    适配器类通过继承或引用适配者的对象,把适配者接口转换成目标接口

    class Target {
     public:
      virtual ~Target() = default;
    
      virtual std::string Request() const {
        return "Target: The default target's behavior.";
      }
    };
    
    class Adaptee {
     public:
      std::string SpecificRequest() const {
        return ".eetpadA eht fo roivaheb laicepS";
      }
    };
    
    class Adapter : public Target {
     private:
      Adaptee *adaptee_;
    
     public:
      Adapter(Adaptee *adaptee) : adaptee_(adaptee) {}
      std::string Request() const override {
        std::string to_reverse = this->adaptee_->SpecificRequest();
        std::reverse(to_reverse.begin(), to_reverse.end());
        return "Adapter: (TRANSLATED) " + to_reverse;
      }
    };
    
    void ClientCode(const Target *target) {
      std::cout << target->Request();
    }
    

    桥接模式

    例,形状+颜色可以组合成平方级数的类,更好的做法是将其中一个(如颜色)分离成接口(setcolor())。

    组合模式

    树形结构,管理员(非叶节点)与职员(叶节点)

    装饰模式

    在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式。
    包含以下角色:
    1.抽象构件(Component)角色:定义一个抽象接口以规范准备接收附加责任的对象。
    2.具体构件(ConcreteComponent)角色:实现抽象构件,通过装饰角色为其添加一些职责。
    3.抽象装饰(Decorator)角色:继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
    4.具体装饰(ConcreteDecorator)角色:实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。
    采用了装饰模式就只需要为每个装饰品生成一个装饰类即可,所以说就增加对象功能来说,装饰模式比生成子类实现更为灵活。

    class Component {
     public:
      virtual ~Component() {}
      virtual std::string Operation() const = 0;
    };
    
    class ConcreteComponent : public Component {
     public:
      std::string Operation() const override {
        return "ConcreteComponent";
      }
    };
    
    class Decorator : public Component {
     protected:
      Component* component_;
    
     public:
      Decorator(Component* component) : component_(component) {
      }
      std::string Operation() const override {
        return this->component_->Operation();
      }
    };
    
    class ConcreteDecoratorA : public Decorator {
     public:
      ConcreteDecoratorA(Component* component) : Decorator(component) {
      }
      std::string Operation() const override {
        return "ConcreteDecoratorA(" + Decorator::Operation() + ")";
      }
    };
    
    class ConcreteDecoratorB : public Decorator {
     public:
      ConcreteDecoratorB(Component* component) : Decorator(component) {
      }
    
      std::string Operation() const override {
        return "ConcreteDecoratorB(" + Decorator::Operation() + ")";
      }
    };
    

    外观模式

    外观模式最简单,它使得两种不同的类不用直接交互,而是通过一个中间件——也就是外观类——间接交互。外观类中只需要暴露简洁的接口,隐藏内部的细节,所以说白了就是封装的思想。

    // 外观角色, 封装了三个子系统的方法
    class Facade {
    public:
        void method() {
            obj1->method1();
            obj2->method2();
            obj3->method3();
        }
    private:
        SubSystem01 *obj1 = new SubSystem01();
        SubSystem02 *obj2 = new SubSystem02();
        SubSystem03 *obj3 = new SubSystem03();
    };
    

    享元模式

    当系统中多处需要同一组信息时,可以把这些信息封装到一个对象中,然后对该对象进行缓存,这样,一个对象就可以提供给多出需要使用的地方,避免大量同一对象的多次创建,降低大量内存空间的消耗。
    享元模式其实是工厂方法模式的一个改进机制,享元模式同样要求创建一个或一组对象,并且就是通过工厂方法模式生成对象的,只不过享元模式为工厂方法模式增加了缓存这一功能。

    代理模式

    1.抽象主题(Subject)类:通过接口或抽象类声明真实主题和代理对象实现的业务方法。
    2.真实主题(Real Subject)类:实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。
    3.代理(Proxy)类:提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或扩展真实主题的功能。

    行为模式

    类和对象如何交互,及划分责任和算法。

    观察者模式

    1. 拆分为两个部分: 独立于其他代码的核心功能将作为发布者; 其他代码则将转化为一组订阅类
    2. 声明订阅者接口。 该接口至少应声明一个 update方法。
    3. 声明发布者接口并定义一些接口来在列表中添加和删除订阅对象。 将列表放置在直接扩展自发布者接口的抽象类中是显而易见的。

    迭代器模式

    备忘录模式

    模板方法模式

    父类定义模板方法以及具体的各个方法;子类重写各个方法。

    状态模式

    类似状态机,为每个状态实现一个类

    责任链模式

    class Handler {
     public:
      virtual Handler *SetNext(Handler *handler) = 0;
      virtual std::string Handle(std::string request) = 0;
    };
    
    class AbstractHandler : public Handler {
    private:
      Handler *next_handler_;
    
    public:
      AbstractHandler() : next_handler_(nullptr) {
      }
      Handler *SetNext(Handler *handler) override {
        this->next_handler_ = handler;
        return handler;
      }
      std::string Handle(std::string request) override {
        if (this->next_handler_) {
          return this->next_handler_->Handle(request);
        }
        return {};
      }
    };
    /**
     * All Concrete Handlers either handle a request or pass it to the next handler
     * in the chain.
     */
    class MonkeyHandler : public AbstractHandler {
     public:
      std::string Handle(std::string request) override {
        if (request == "Banana") {
          return "Monkey: I'll eat the " + request + ".
    ";
        } else {
          return AbstractHandler::Handle(request);
        }
      }
    };
    

    命令模式

    不常用,暂忽略

    中介者模式

    中介者会逐渐变庞大,演变成上帝对象。

    策略模式

    策略模式定义一族算法类,将每个算法分别封装起来,让它们可以互相替换。策略模式可以使算法的变化独立于使用它们的客户端(这里的客户端代指使用算法的代码)。策略模式用来解耦策略的定义、创建、使用。实际上,一个完整的策略模式就是由这三个部分组成的。
    最常见的应用场景是,利用它来避免冗长的if-else或switch分支判断。

    模板方法模式

    模板方法模式在一个方法中定义一个算法骨架,并将某些步骤推迟到子类中实现。

    访问模式

    访问者模式建议将新行为放入一个名为访问者的独立类中, 而不是试图将其整合到已有类中。
    不常用。

    设计模式总结

      1. 创建型模式
        单例模式、工厂模式频繁使用
      1. 结构型模式
        外观模式非常常用,间接封装,作用于整个对象子系统,可封装多个对象
        适配器模式能为被封装对象提供不同的接口,只封装一个对象
        代理模式能为对象提供相同的接口
        装饰模式则能为对象提供加强的接口,还支持递归组合
        享元模式展示了如何生成大量的小型对象
      1. 行为模式
        观察者模式支持订阅与发布
        迭代器模式支持集合的遍历
        备忘录模式即快照模式,支持恢复、防丢失
        状态模式实现了状态机,实现方式有 ifelse法、查表法、状态模式法,对于状态少业务逻辑多的场景首选状态模式
        责任链模式,继承包含了next_handler_变量的父类, 通过set_next_handler传导请求
        中介者模式,中介者会逐渐变庞大,演变成上帝对象。
        策略模式...
        模板方法模式...

    设计模式准则

    • 开闭原则:一个软件实体如类、模块和函数应该对修改封闭,对扩展开放。
    • 单一职责原则:类只做一件事,一个类应该只有一个引起它修改的原因。
    • 里氏替换原则:子类应该可以完全替换父类。也就是说在使用继承时,只扩展新功能,而不要破坏父类原有的功能。
    • 依赖倒置原则:细节应该依赖于抽象,抽象不应依赖于细节。把抽象层放在程序设计的高层,并保持稳定,程序的细节变化由低层的实现层来完成。
    • 迪米特法则:又名「最少知道原则」,一个类不应知道自己操作的类的细节,换言之,只和朋友谈话,不和朋友的朋友谈话。
    • 接口隔离原则:客户端不应依赖它不需要的接口。如果一个接口在实现时,部分方法由于冗余被客户端空实现,则应该将接口拆分,让实现类只需依赖自己需要的接口方法。

      ref: https://www.cnblogs.com/linuxAndMcu/p/12408437.html
    诸神对凡人心生艳羡,厌倦天堂。
  • 相关阅读:
    分布式页面静态化
    采用rabbitMq消息推送方案
    rabbitmq的使用介绍和注意事项目
    redis面试题
    Redis 使用入门
    git使用介绍
    JavaSE11(1)采用类
    原型模式
    javaSE 10(2)
    javaSE 10
  • 原文地址:https://www.cnblogs.com/dirge/p/14656085.html
Copyright © 2020-2023  润新知