Resumen de patrones de diseño de C ++ (23 tipos) e implementación de código

Tabla de contenido

Siete principios de patrones de diseño:

Principio de apertura y cierre:

Principio de responsabilidad única:

Principio de sustitución de Richter:

Principio de inversión de dependencia:

Principio de aislamiento de interfaz:

Principio Dimit (Principio Menos Conocido):

Principios de reutilización sintética:

Tres modos principales y sus características:

Modo creacional:

Patrón estructural:

Patrón de comportamiento:

--------------------Soy una línea divisoria, el siguiente es el modo creativo------------------ - ----

Modo intérprete:

ventaja:

defecto:

Escena aplicable:

Código de implementación:

Modo constructor:

defecto:

ventaja:

Comparado con el modo de fábrica:

Escena aplicable:

Código de implementación:

Patrón de fábrica simple:

ventaja:

defecto:

Método de fábrica:

Código de implementación:

Modo prototipo:

ventaja:

defecto:

Escena aplicable:

Código de implementación:

Modo singleton:

ventaja:

defecto:

paso:

detalle:

Código de implementación:

--------------------Yo soy la línea divisoria, el siguiente es el patrón estructural------------------ - ----

Modo adaptador:

ventaja:

defecto:

Escena aplicable:

Precauciones:

Código de implementación:

Modo Puente:

ventaja:

defecto:

Escena aplicable:

Código de implementación:

Modo de entidad combinado:

ventaja:

defecto:

Escena aplicable:

Código de implementación:

Patrón decorador:

ventaja:

defecto:

Escena aplicable:

Código de implementación:

Modo de apariencia (modo fachada):

ventaja:

defecto:

Escena aplicable:

Código de implementación:

Modo de peso mosca:

ventaja:

defecto:

Escena aplicable:

Código de implementación:

Modo agente:

ventaja:

defecto:

Escena aplicable:

Código de implementación:

--------------------------Soy una línea divisoria, lo que sigue es el patrón de comportamiento------------ -- ------

Modelo de cadena de responsabilidad:

ventaja:

defecto:

Escena aplicable:

Código de implementación:

Modo de comando:

ventaja:

defecto:

Escena aplicable:

Código de implementación:

Modo intérprete:

ventaja:

defecto:

Escena aplicable:

Código de implementación:

Patrón de iterador:

ventaja:

defecto:

Escena aplicable:

Código de implementación:

Modelo mediador:

ventaja:

defecto:

Escena aplicable:

Código:

Modo nota:

ventaja:

defecto:

Escena aplicable:

Código de implementación:

Modo observador:

ventaja:

defecto:

Escena aplicable:

Código:

Modo de estado:

ventaja:

defecto:

Escena aplicable:  

Código:

Modo estrategia:

ventaja:

defecto:

Escena aplicable:

Precauciones:

Código:

Modo de plantilla:

ventaja:

defecto:

Escena aplicable:

Código:

Modo visitante:

ventaja:

defecto:

Escena aplicable:

Código:

referencia:


Siete principios de patrones de diseño:

Principio de apertura y cierre:

        Abierto para ampliación, cerrado para modificación. Cuando es necesario expandir el programa, el código original no se puede modificar, pero el código original se puede expandir para lograr el efecto de intercambio en caliente.

Principio de responsabilidad única:

        No debe haber más de una razón para los cambios de clase, lo que significa que cada clase debe implementar una única responsabilidad, si no, la clase debe dividirse.


Principio de sustitución de Richter:

        Es uno de los principios básicos del diseño orientado a objetos. En cualquier lugar donde pueda aparecer una clase base, ciertamente puede aparecer una subclase. Es la piedra angular de la herencia y la reutilización. Solo cuando la clase derivada puede reemplazar a la clase base y la función de la unidad de software no se ve afectada, la clase base se puede reutilizar verdaderamente y la clase derivada también puede agregar nuevos comportamientos sobre la base. de acumulación. Es un complemento del "principio de apertura y cierre". El paso clave para implementar el principio de apertura y cierre es la abstracción, y la relación de herencia entre las clases base y las subclases es la implementación específica de la abstracción, por lo que el principio de sustitución de Liskov es una especificación de los pasos específicos para lograr la abstracción.


Principio de inversión de dependencia:

        Ésta es la base del principio de apertura y cierre. El contenido específico es: la programación orientada a interfaz se basa en la abstracción en lugar de la concreción. Cuando se utiliza una clase concreta al escribir código, no interactúa con la clase concreta, sino con la interfaz de nivel superior de la clase concreta.


Principio de aislamiento de interfaz:

        No hay métodos en cada interfaz que no sean utilizados por las subclases pero que deban implementarse, de lo contrario, la interfaz debe dividirse. Usar múltiples interfaces aisladas es mejor que usar una sola interfaz.


Principio Dimit (Principio Menos Conocido):

        Cuanto menos sepa una clase sobre las clases de las que depende, mejor. No importa cuán compleja sea la clase dependiente, la lógica debe encapsularse dentro del método y proporcionarse al exterior a través del método público. De esta manera, cuando la clase dependiente cambia, la clase puede verse mínimamente afectada.


Principios de reutilización sintética:

        ​ ​ ​ Intente utilizar composición/agregación en lugar de herencia.

Tres modos principales y sus características:

Modo creacional:

        Resume el proceso de creación de instancias. Ayudan a que un sistema se vuelva independiente de cómo se crean, componen y representan sus objetos.

(Patrón de fábrica abstracto, patrón de constructor, patrón de fábrica, patrón de prototipo, patrón singleton)

Patrón estructural:

        Implica cómo combinar clases y objetos para obtener estructuras más grandes. El patrón creacional se centra en la creación de instancias de una clase u objeto; el patrón estructural se centra en la combinación de múltiples clases u objetos en objetos más complejos para construir objetos de manera más flexible.

(Modo adaptador, modo puente, modo entidad combinada, modo decorador, modo apariencia, modo peso mosca, modo proxy)

Patrón de comportamiento:

        Implica la distribución de responsabilidades entre algoritmos y objetos. Describe no solo los patrones de objetos y clases, sino también los patrones de comunicación entre ellos. Utilice el mecanismo de herencia para distribuir el comportamiento entre clases.

(Patrón de cadena de responsabilidad, patrón de comando, patrón de intérprete, patrón de iterador, patrón de mediador, patrón de recuerdo, patrón de observador, patrón de estado, patrón de estrategia, patrón de plantilla, patrón de visitante)

--------------------Soy una línea divisoria, el siguiente es el modo creativo------------------ - ----

Modo intérprete:

Se refiere a un idioma dado (expresión), definiendo una representación de su gramática y definiendo un intérprete, utilizando al intérprete para interpretar oraciones (expresiones) en el idioma.

ventaja:

    1. Tiene buena escalabilidad. La traducción de gramática se implementa a través de clases y la extensión de las clases puede ampliar sus capacidades de interpretación.

    2. La dificultad de implementación es baja: cada clase de nodo de expresión en el árbol de sintaxis tiene cierta similitud, por lo que es relativamente fácil de implementar.

defecto:

    1. Baja eficiencia de ejecución. Generalmente hay una gran cantidad de bucles y declaraciones recursivas en el intérprete, cuando las oraciones que se interpretan son complejas, el rendimiento del programa se ve muy afectado.

    2. Problema de expansión de clases. Cuando hay más reglas, el número de clases también se expande.

Escena aplicable:

    Cuando un tipo específico de problema ocurre con suficiente frecuencia, por ejemplo, explicación de sintaxis simple, compilador, cálculo de expresiones operativas, expresiones regulares, procesamiento de registros: cuando se utiliza un lenguaje de secuencias de comandos o un lenguaje de programación para procesar registros,

    Se generará una gran cantidad de informes y es necesario analizar los registros y generar informes.

    Los formatos de registro de cada servicio son diferentes, pero los elementos de los datos son los mismos. En este caso, la principal solución para resolver los problemas anteriores a través de programas es utilizar el modo intérprete, que rara vez se utiliza en proyectos diarios.

Compare con el patrón del adaptador: los dos patrones son similares, pero el patrón del adaptador no requiere conocimiento previo de las reglas del adaptador. El modo de intérprete requiere que las reglas se escriban con anticipación y que la interpretación se realice de acuerdo con las reglas.

Código de implementación:

#include<iostream>
#include<list>
#include<vector>
#include<algorithm>

class Context{
public:
    Context(int num){
        m_num=num;
    }

    void setNum(int num){
        m_num=num;
    }
    int getNum(){
        return m_num;
    }
    void setRes(int res){
        m_res=res;
    }
    int getRes(){
        return m_res;
    }

private:
    int m_num,m_res;

};

class Expression{
public:
    virtual void interpreter(Context* context) =0;
};

class PlusExpression :public Expression{
public:
    virtual void interpreter(Context* context){
        int num=context->getNum();
        num++;
        context->setNum(num);
        context->setRes(num);
    }
};

class MinusExpression :public Expression{
public:
    virtual void interpreter(Context* context){
        int num =context->getNum();
        num--;
        context->setNum(num);
        context->setRes(num);
    }
};


int
main(){

    Context* pcxt =new Context(10);
    Expression* e1=new PlusExpression();

    e1->interpreter(pcxt);
    std::cout<<"PlusExpression:"<<pcxt->getRes()<<std::endl;

    Expression* e2 =new MinusExpression();
    e2->interpreter(pcxt);
    std::cout<<"MinusExpression:"<<pcxt->getRes()<<std::endl;
    delete e1,e2,pcxt;

    return 0;
}

Modo constructor:

Separar el proceso de construcción de un objeto complejo de su representación permite que el mismo proceso de construcción cree diferentes representaciones.

 Los usuarios solo necesitan especificar el tipo que se va a construir para obtener la instancia de producto correspondiente a ese tipo, y no les importan los detalles del proceso de construcción.

Es decir, cómo construir gradualmente un objeto que contiene múltiples componentes: el mismo proceso de construcción puede crear diferentes productos.

defecto:

        ​ ​ 1. Aumentó el número de clases: generando objetos Builder redundantes

        ​ ​ 2. Dificultad en la modificación interna: si el producto cambia internamente, el constructor también debe modificarlo en consecuencia.

ventaja:

        ​ ​ 1. Buena encapsulación: separación de creación y uso

        ​ ​ 2. Buena escalabilidad: las clases de construcción son independientes entre sí y están desacopladas hasta cierto punto

Comparado con el modo de fábrica:

    El enfoque es diferente: el patrón constructor se centra más en el proceso de llamada al método; el patrón fábrica se centra en la creación de productos y no le importa el orden en el que se utilizan los métodos.

    ​ Diferentes puntos fuertes en la creación de objetos: Diferentes puntos fuertes en la creación de objetos. El patrón constructor puede crear productos complejos, que se componen de varios componentes complejos. El patrón fábrica crea los mismos objetos de instancia.

Escena aplicable:

        Estructura compleja: el objeto tiene una estructura interna muy compleja con muchos atributos. Creación y uso separados: quiero separar la creación y el uso de objetos complejos.

        El patrón constructor es adecuado cuando la creación de un objeto requiere muchos pasos. Cuando crear un objeto solo requiere un método simple, el patrón de fábrica es adecuado.

Código de implementación:

#include<iostream>
#include<memory.h>
#include<string>

class PersonBuilder {
public:
    virtual void buildHead() {}
    virtual void buildBody() {}
    virtual void buildArm() {}
    virtual void buildLeg() {}
    PersonBuilder(){}
    PersonBuilder(std::string g, std::string p) {
        this->g = g;
        this->p = p;
    }
    virtual ~PersonBuilder() {};

    std::string g, p;
};

class PersonThinBuilder : public PersonBuilder {
public:
    PersonThinBuilder(std::string g, std::string p){
        this->g = g;
        this->p = p;
    }
    void buildHead() {
        std::cout << "瘦子 画头" << std::endl;
    }
    void buildBody() {
        std::cout << "瘦子 画身体" << std::endl;
    }
    void buildArm() {
        std::cout << "瘦子 画胳膊" << std::endl;
    }
    void buildLeg() {
        std::cout << "瘦子 画大腿" << std::endl;
    }

};

class PersonFatBuilder : public PersonBuilder {
public:
    PersonFatBuilder() {}
    PersonFatBuilder(std::string g, std::string p) {
        this->g = g;
        this->p = p;
    }
    
    void buildHead() {
        std::cout << "胖子 画头" << std::endl;
    }
    void buildBody() {
        std::cout << "胖子 画身体" << std::endl;
    }
    void buildArm() {
        std::cout << "胖子 画胳膊" << std::endl;
    }
    void buildLeg() {
        std::cout << "胖子 画大腿" << std::endl;
    }
};

class PersonDirector {
public:
    PersonDirector(PersonBuilder* pb) {
        this->pb = pb;
    }
    void createPerson() {
        pb->buildHead();
        pb->buildBody();
        pb->buildArm();
        pb->buildLeg();
    }
private:
    PersonBuilder* pb;
};


int
main() {

    PersonThinBuilder* pt = new PersonThinBuilder("画瘦子", "红笔");
    PersonDirector* pd = new PersonDirector(pt);
    pd->createPerson();

    return 0;
}

Patrón de fábrica simple:

        Cualquier producto se puede producir mediante el control de parámetros.

ventaja:

        Sencillo y crudo, intuitivo y fácil de entender. Utilice una fábrica para producir cualquier producto bajo la misma estructura jerárquica.

defecto:

        ​ ​ 1. Todo se produce en conjunto: demasiados productos generarán una gran cantidad de código.

        ​ ​ 2. El principio de apertura y cierre (abierto para expansión, cerrado para modificación) no es muy bueno, si desea agregar nuevos productos, debe modificar el método de fábrica.

Método de fábrica:

        Defina una interfaz para crear objetos, pero deje que la subclase decida qué tipo de objeto crear y utilice varias fábricas para producir productos fijos específicos.

Código de implementación:

#include <iostream>
#include <string>
#include <memory>
class Fruit {
 public:
    Fruit(){}
    virtual void show() = 0;
};
class Apple : public Fruit {
 public:
    Apple() {}
    virtual void show() {
    std::cout << "我是⼀个苹果" << std::endl;
 }
};
class Banana : public Fruit {
 public:
    Banana() {}
    virtual void show() {
        std::cout << "我是⼀个⾹蕉" << std::endl;
    }
};
class FruitFactory {
 public:
    static std::shared_ptr<Fruit> create(const std::string &name) {
    if (name == "苹果") {
        return std::make_shared<Apple>();
    }else if(name == "⾹蕉") {
        return std::make_shared<Banana>();
    }
    return std::shared_ptr<Fruit>();
 }
};
int main()
{
    std::shared_ptr<Fruit> fruit = FruitFactory::create("苹果");
    fruit->show();
    fruit = FruitFactory::create("⾹蕉");
    fruit->show();
    return 0;
}

Modo prototipo:

        El modo prototipo también proporciona la función de autorreplicación, lo que significa que se pueden crear nuevos objetos a partir de objetos existentes.

ventaja:

    1. Los objetos se pueden clonar sin estar acoplados a las clases concretas a las que pertenecen.

    2. Puede clonar el prototipo pregenerado para evitar ejecutar repetidamente el código de inicialización.

    3. Es más fácil generar objetos complejos.

    4. Se pueden manejar diferentes configuraciones de objetos complejos de formas distintas a la herencia.

defecto:

    1. Necesitas configurar un método de clonación para cada clase.

    2. El método de clonación se encuentra dentro de la clase. Al modificar una clase existente, es necesario modificar el código, lo que viola el principio de apertura y cierre.

    3. Al realizar una copia profunda, es necesario escribir código más complejo. Cuando hay múltiples anidamientos entre objetos, para lograr una clonación profunda, las clases correspondientes a cada capa de objetos deben admitir la clonación profunda, que es compleja de implementar.

Escena aplicable:

    1. Cuando los objetos son iguales o similares y solo difieren en algunos atributos individuales

    2. El costo de crear objetos es alto, como un tiempo de inicialización prolongado, demasiado uso de CPU o demasiados recursos de red, es necesario optimizar los recursos.

    3. La creación de un objeto requiere preparación frecuente de datos o permisos de acceso, etc., lo que requiere un mejor rendimiento o una mayor seguridad.

    4. Este tipo de objeto se usa ampliamente en el sistema y cada persona que llama necesita reasignar sus atributos.

Código de implementación:

#include<iostream>
#include<memory.h>
#include<string>

class Prototype{
public:
    virtual ~Prototype(){}
    virtual Prototype* Clone()const=0;
protected:
    Prototype(){}
};

class ConcretePrototype:public Prototype{
public:
    ConcretePrototype(){}
    ConcretePrototype(const ConcretePrototype& cp){
        std::cout<<"ConcretePrototype copy ..."<<std::endl;
    }
    ~ConcretePrototype();
    Prototype* Clone()const{
        return new ConcretePrototype(*this);
    }
};

int 
main(){

    Prototype* p=new ConcretePrototype();
    Prototype* p1=p->Clone();

    return 0;
}

Modo singleton:

        Una clase solo crea un objeto único, es decir, puede crearse una vez y usarse varias veces.

ventaja:

    1. Proporciona acceso controlado a una instancia única.

    2. Dado que solo hay un objeto en el sistema, se pueden ahorrar recursos del sistema. Para algunos objetos que deben crearse y destruirse con frecuencia, el modo singleton sin duda puede mejorar el rendimiento del sistema.

    3.Permitir un número variable de instancias

defecto:

    1. Dado que no hay una capa de abstracción en el patrón singleton, es muy difícil extender la clase singleton.

    2. La acusación de clase única es demasiado grave, lo que viola el "principio de responsabilidad única" hasta cierto punto.

    3. El abuso de singleton traerá algunos problemas negativos. Por ejemplo, para ahorrar recursos, el objeto del grupo de conexiones de la base de datos está diseñado como una clase singleton, lo que puede hacer que demasiados programas compartan el objeto del grupo de conexiones.

    Y se produce un desbordamiento del grupo de conexiones; si el objeto instanciado no se utiliza durante mucho tiempo, el sistema lo considerará basura y será reciclado, lo que provocará la pérdida del estado del objeto.

paso:

    1. Privatización de los constructores

    2. Agregue una variable de puntero privado estático de la clase actual.

    3. Proporcionar una interfaz externa estática que permita a los usuarios obtener el modo singleton.

detalle:

    1. Modo hambriento: crea una instancia de sí mismo cuando se carga la clase. Su ventaja es que no necesita considerar problemas de acceso de subprocesos múltiples y puede garantizar la unicidad de la instancia.

        Dado que se creó desde el principio, es mejor que el estilo perezoso en términos de velocidad de llamada y tiempo de respuesta. Pero si el sistema necesita usar el objeto de instancia en tiempo de ejecución

        El objeto se creará cuando se cargue la clase. En términos de eficiencia de utilización de recursos, el estilo hambriento no es tan bueno como el estilo perezoso. Además, dado que es necesario crear un objeto singleton cuando se carga el sistema, el tiempo de carga es relativamente largo.

    2. Modo diferido: creado cuando se usa por primera vez, no es necesario ocupar recursos del sistema todo el tiempo y se logra la carga diferida, pero se debe abordar el problema del acceso simultáneo de múltiples subprocesos, especialmente cuando

        Como controlador de recursos, una clase singleton debe implicar la inicialización de recursos durante la creación de instancias, y es probable que la inicialización de recursos lleve mucho tiempo, lo que significa que pueden ocurrir varios subprocesos por primera vez al mismo tiempo.

        La probabilidad de hacer referencia a clases como esta aumenta y debe controlarse mediante un mecanismo de doble verificación, lo que puede afectar el rendimiento del sistema.

Código de implementación:

#include<iostream>
#include<memory.h>
#include<string>
//饿汉式
class SingletonHungry{
public:
    static SingletonHungry* getInstance(){
        return pSingleton;
    }
private:
    SingletonHungry(){}
    static SingletonHungry* pSingleton;
};
SingletonHungry* SingletonHungry::pSingleton=new SingletonHungry;//在加载的时候就创建

class SingletonLazy{
public:
    static SingletonLazy* getInstance(){
        if(pSingleton==nullptr){
            pSingleton=new SingletonLazy;
        }
        return pSingleton;
    }
private:
    SingletonLazy(){}
    static SingletonLazy* pSingleton;
};
SingletonLazy* SingletonLazy::pSingleton=nullptr;



int 
main(){

    SingletonHungry* test1=SingletonHungry::getInstance();
    SingletonHungry* test2=SingletonHungry::getInstance();
    if(test1==test2) std::cout<<"饿汉单例模式"<<std::endl;
    else std::cout<<"Not 饿汉单例模式"<<std::endl;

    SingletonLazy* test3=SingletonLazy::getInstance();
    SingletonLazy* test4=SingletonLazy::getInstance();
    if(test3==test4) std::cout<<"懒汉单例模式"<<std::endl;
    else std::cout<<"Not 懒汉单例模式"<<std::endl;



    return 0;
}

--------------------Yo soy la línea divisoria, el siguiente es el patrón estructural------------------ - ----

Modo adaptador:

        Combina las funciones de dos interfaces independientes, convierte la interfaz de una clase en otra interfaz esperada por el cliente, de modo que clases o funciones originalmente incompatibles puedan operar juntas y es un puente entre dos interfaces incompatibles.

ventaja:

    1. Puede resolver eficazmente problemas de compatibilidad de interfaces

    2. Gran flexibilidad

defecto:

    1. El uso excesivo de adaptadores hará que el sistema sea muy complicado y difícil de entender en su totalidad.

        ​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ ​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​

        Por tanto, si no es necesario, puedes reconstruir el sistema directamente sin utilizar el adaptador.

Escena aplicable:

    1. Durante el proceso de iteración del software, se produce una incompatibilidad de interfaz.

    2. Quiere crear una clase que pueda reutilizarse para trabajar con algunas clases que no están muy relacionadas entre sí, incluidas algunas clases que pueden introducirse en el futuro. Estas clases fuente no necesariamente tienen interfaces consistentes.

    3. Inserte una clase en otra clase mediante la conversión de interfaz.

    (Por ejemplo, entre tigres y pájaros, ahora hay un tigre volador. Sin la necesidad de agregar entidades, agregue un adaptador para contener un objeto de tigre e implementar la interfaz voladora).

Precauciones:

        ​ ​ ​ Los adaptadores no se agregan durante el diseño del programa, sino para resolver problemas en proyectos actualmente en servicio.

Código de implementación:

#include<iostream>
#include<memory.h>
#include<string>

class Target{
public:
    Target(){}
    virtual ~Target(){}
    virtual void Request(){
        std::cout<<"Target::Request"<<std::endl;
    }
};

class Adaptee{
public:
    Adaptee(){}
    ~Adaptee(){}
    void SpecificRequest(){
        std::cout<<"Adaptee::SpecificRequest"<<std::endl;
    }
};

class Adapter:public Target{
public:
    Adapter(Adaptee* ade){
        _ade=ade;
    }
    ~Adapter(){}
    void Request(){
        _ade->SpecificRequest();
    }
private:
    Adaptee* _ade;
};



int
main(){

    Adaptee* ade=new Adaptee;
    Target* adt =new Adapter(ade);
    adt->Request();
    return 0;
}

Modo Puente:

        ​ ​ Separe la abstracción y la implementación para que las dos puedan cambiar de forma independiente. El modo puente convierte las relaciones de herencia en relaciones de combinación. Se logró la separación de abstracción e implementación.

ventaja:

    1. Extraiga la realidad e implemente la abstracción para que la implementación específica del objeto dependa de la abstracción, lo que satisface el principio de inversión de dependencia.

    2. Extraiga los cambios que se pueden compartir para reducir la información duplicada en el código.

    3. La implementación específica del objeto puede ser más flexible y puede cumplir con los requisitos de múltiples factores.

    4. Se mejoró la escalabilidad del sistema, si es necesario expandir una determinada dimensión, solo es necesario agregar una interfaz de clase de implementación o una clase de implementación específica, y no afectará la otra dimensión, cumpliendo con el principio de apertura y cierre.

defecto:

    1. Aumentará la dificultad de comprender y diseñar el sistema, porque la relación se establece en la capa abstracta y es necesario diseñar y programar en la capa abstracta desde el principio.

    2. Se requiere identificar correctamente dos o más dimensiones que cambian de forma independiente en el sistema. Cómo identificar con precisión las dos dimensiones en el sistema es la dificultad para aplicar el modo puente.

Escena aplicable:

    1. El sistema necesita agregar más flexibilidad entre abstracción y concreción para evitar establecer una relación de herencia estática entre los dos niveles.A través del modo puente, pueden establecer una relación de asociación en la capa de abstracción.

    2. Una clase tiene dos o más dimensiones que cambian de forma independiente y estas dos o más dimensiones deben expandirse de forma independiente.

    3. Para aquellos sistemas que no quieren utilizar la herencia o donde el número de clases del sistema aumenta considerablemente debido a la herencia multinivel.

// Tome el software de dibujo de Windows como ejemplo. Pen es una clase base que expone la interfaz drow al mundo exterior y las líneas dibujadas son gruesas, medianas y delgadas. Los colores se dividen en rojo, amarillo y azul. Si se implementa mediante herencia. Entonces se necesitan 3*3 = 9 subclases para la permutación y combinación. En su lugar, utilice el modo puente. Sólo se necesitan 6. Evidentemente cuantos más espesores y colores mayores serán las ventajas.

Código de implementación:

#include<iostream>
#include<string>
class AbstractionImp {
public:
    virtual ~AbstractionImp() {}
    virtual void Operation() = 0;
protected:
    AbstractionImp() {}
};

class Abstraction {
public:
    virtual ~Abstraction() {}
    virtual void Operation() = 0;
protected:
    Abstraction() {}
};

class RefinedAbstaction :public Abstraction {
public:
    RefinedAbstaction(AbstractionImp* imp) {
        _imp = imp;
    }
    ~RefinedAbstaction() {}
    void Operation() {
        _imp->Operation();
    }
private:
    AbstractionImp* _imp;
};

class ConcreteAbstractionImpA : public AbstractionImp {
public:
    ConcreteAbstractionImpA() {}
    ~ConcreteAbstractionImpA() {}
    virtual void Operation() {
        std::cout << "ConcreteAbstractionImpA...." << std::endl;
    }

};

class ConcreteAbstractionImpB : public AbstractionImp {
public:
    ConcreteAbstractionImpB() {}
    ~ConcreteAbstractionImpB() {}
    virtual void Operation() {
        std::cout << "ConcreteAbstractionImpB...." << std::endl;
    }
};

int
main() {

    AbstractionImp* imp = new ConcreteAbstractionImpA();
    Abstraction* abs = new RefinedAbstaction(imp);
    abs->Operation();

    return 0;
}

Modo de entidad combinado:

        Es un patrón de diseño estructural que se puede utilizar para combinar objetos en una estructura de árbol y utilizarlos como objetos independientes.

ventaja:

    1. Permite al cliente procesar objetos individuales y objetos combinados de manera unificada.

    2. Le permite agregar nuevos tipos de componentes más fácilmente

defecto:

    1. Puede que su diseño sea demasiado genérico. A veces, solo los componentes de hoja necesitan definir ciertas operaciones, pero debido a los puntos en común, estas operaciones deben definirse en todos los componentes.

Escena aplicable:

    Por ejemplo: en las interfaces gráficas de usuario, muchas interfaces gráficas de usuario utilizan el modo combinado para organizar y administrar componentes como ventanas y paneles. Los sistemas de archivos, que normalmente utilizan patrones de composición para representar jerarquías de archivos y carpetas,

        Los documentos XML/HTML también pueden utilizar el modo combinado para representar su estructura de árbol.

Código de implementación:

#include<iostream>
#include<algorithm>
#include<memory.h>
#include<string>
#include<list>

class Component{
public:
    Component(){}
    virtual ~Component(){}
    virtual void Operation()=0;
    virtual void Add(Component* pChild){};
    virtual void Remove(Component* pChild){};
    virtual Component* GetChild(int nIndex){ 
        return nullptr;
    };

};

class Leaf: public Component{
public:
    Leaf(){}
    virtual ~Leaf(){}
    virtual void Operation(){
        std::cout<<"Operation by leaf\n";
    }
};

class Composite:public Component{
public:
    Composite(){}
    virtual ~Composite(){
        std::list<Component*>::iterator iter1,iter2,temp;
        for(iter1 =m_ListOfComponent.begin(),iter2=m_ListOfComponent.end();iter1!=iter2;){
            temp=iter1;
            ++iter1;
            delete *temp;
        }
    }
    virtual void Operation(){
        std::cout<<"Operation by Composite\n";
        std::list<Component*>::iterator iter1,iter2;
        for( iter1=m_ListOfComponent.begin(), iter2=m_ListOfComponent.end(); iter1!=iter2; ++iter1){
            (*iter1)->Operation();
        }
    }
    virtual void Add(Component* pChild){
        m_ListOfComponent.push_back(pChild);
    }
    virtual void Remove(Component* pChild){
        std::list<Component*>::iterator iter;
        iter=find(m_ListOfComponent.begin(),m_ListOfComponent.end(),pChild);
        if(m_ListOfComponent.end()!=iter){
            m_ListOfComponent.erase(iter);
        }
    }
    virtual Component* GetChild(int nIndex){
        if(nIndex <=0 ||nIndex > m_ListOfComponent.size()) return nullptr;
        std::list<Component*>::iterator iter1,iter2;
        int i;
        for(i=1,iter1=m_ListOfComponent.begin(),iter2=m_ListOfComponent.end() ; iter1!=iter2 ; ++iter1, ++i){
            if(i == nIndex) break;
        }
        return *iter1;
    }
private:
    std::list<Component*> m_ListOfComponent;
};


int 
main(){

    Leaf* pLeaf1=new Leaf();
    Leaf* pLeaf2=new Leaf();
    Composite* pComposite=new Composite;
    pComposite->Add(pLeaf1);
    pComposite->Add(pLeaf2);
    pComposite->Operation();
    pComposite->GetChild(2)->Operation();
    
    return 0;
}

Patrón decorador:

        Sin cambiar el archivo de clase original ni utilizar la herencia, expanda dinámicamente un objeto para mejorar o agregar objetos.

ventaja:

    1. Buena flexibilidad: en comparación con la herencia, el modo decorador es más flexible a la hora de expandir funciones de objetos.

    2. Buena escalabilidad, diferentes combinaciones de decoración pueden crear una variedad de objetos y evitar la explosión de clases.

    3. Cumplir con los principios de apertura y cierre y los principios de reutilización que cumplen con los requisitos del patrón de diseño.

    4. Buena transparencia: el cliente apunta a operaciones abstractas y es invisible para el contenido de implementación específico.

defecto:

    1. Alta complejidad. El diseño de decoradores suele ser muy complejo y requiere altos niveles de habilidades de desarrollador.

Escena aplicable:

    Por ejemplo, interfaz gráfica de usuario: muchas interfaces gráficas de usuario utilizan el patrón decorador para agregar dinámicamente nuevos comportamientos y estilos. Compresión de datos, registro, etc.

Código de implementación:

#include<iostream>
#include<memory>
#include<string>

class AbstractHero{
public:
    virtual void showStatus()=0;
    int mHp,mMp,mAt,mDf;
};

class HeroA:public AbstractHero{
public:
    HeroA(){
        mHp=0,mMp=0,mAt=0,mDf=0;
    }
    virtual void showStatus(){
        std::cout<<"血量:"<<mHp<<std::endl;
        std::cout<<"魔法:"<<mMp<<std::endl;
        std::cout<<"攻击:"<<mAt<<std::endl;
        std::cout<<"防御:"<<mDf<<std::endl;
    }
};

//英雄穿上某个装饰物,那么也还是一个英雄
class AbstractEquipment: public AbstractHero{
public:
    AbstractEquipment(AbstractHero* hero){
        pHero=hero;
    }
    virtual void showStatus(){}
    AbstractHero* pHero;
};

//给英雄穿上狂徒铠甲
class KuangtuEquipment:public AbstractEquipment{
public:
    KuangtuEquipment(AbstractHero* hero):AbstractEquipment(hero){}
    //增加新的功能
    void AddKuangtu(){
        std::cout<<"新英雄穿上狂徒之后"<<std::endl;
        this->mHp=this->pHero->mHp;
        this->mMp=this->pHero->mMp;
        this->mAt=this->pHero->mAt;
        this->mDf=this->pHero->mDf+30;
    }
    virtual void showStatus(){
        AddKuangtu();
        std::cout<<"血量:"<<mHp<<std::endl;
        std::cout<<"魔法:"<<mMp<<std::endl;
        std::cout<<"攻击:"<<mAt<<std::endl;
        std::cout<<"防御:"<<mDf<<std::endl;
    }
};


int main(){

    AbstractHero* hero=new HeroA;
    hero->showStatus();
    std::cout<<"------------------------"<<std::endl;
    //给英雄穿上狂徒
    hero=new KuangtuEquipment(hero);
    hero->showStatus();

    return 0;
}

Modo de apariencia (modo fachada):

        se refiere a que la comunicación entre el exterior y el subsistema debe realizarse a través de un objeto de apariencia unificada.

        Proporcionar una interfaz consistente para un conjunto de interfaces en el subsistema y definir una interfaz de alto nivel que haga que el subsistema sea más fácil de usar.

ventaja:

    1. Simplifique la interacción entre el cliente y el subsistema, facilitando al cliente el uso del subsistema.

    2. Puede reducir el acoplamiento entre el cliente y el subsistema, de modo que el cliente no necesita interactuar directamente con el subsistema.

    3. La implementación del subsistema se puede cambiar sin afectar al cliente.

defecto:

    1. El acceso del cliente al subsistema puede estar restringido porque el cliente solo puede acceder al subsistema a través de la clase de apariencia.

    2. Si el diseño no es cuidadoso, puede convertirse en una clase enorme y compleja que es difícil de mantener.

Escena aplicable:

    1. En el desarrollo de software, el patrón de apariencia se usa a menudo para encapsular la biblioteca o marco subyacente y proporcionar una interfaz simple para la capa superior. Esto puede reducir el acoplamiento entre las aplicaciones de la capa superior y las bibliotecas subyacentes, lo que hace que las aplicaciones de la capa superior sean más fáciles de desarrollar y mantener.

    2. En los sistemas operativos, el modo de apariencia también suele utilizarse ampliamente. Por ejemplo, el sistema operativo proporciona una interfaz sencilla para que las aplicaciones puedan acceder fácilmente a los recursos de hardware sin interactuar directamente con los controladores de hardware.

    3. En el desarrollo web, los marcos web generalmente proporcionan a los desarrolladores una interfaz simple, lo que les permite desarrollar fácilmente aplicaciones web sin preocuparse por el protocolo http subyacente y la configuración del servidor.

Código de implementación:

#include<iostream>
#include<string>
#include<memory>

class Television{
public:
    void on(){
        std::cout<<"电视机打开"<<std::endl;
    }
    void off(){
        std::cout<<"电视机关闭"<<std::endl;
    }
};

class Light{
public:
    void on(){
        std::cout<<"灯打开"<<std::endl;
    }
    void off(){
        std::cout<<"灯关闭"<<std::endl;
    }
};

class DVDplayer{
public:
    void on(){
        std::cout<<"DVD打开"<<std::endl;
    }
    void off(){
        std::cout<<"DVD关闭"<<std::endl;
    }
};

//外观模式
class KTVMode{
public:
    KTVMode(){
        pTV=new Television;
        pLight=new Light;
        pDvD=new DVDplayer;
    }
    void onKTV(){
        pTV->on();
        pLight->on();
        pDvD->on();
    }
    ~KTVMode(){
        pTV->off();
        pLight->off();
        pDvD->off();
        delete pTV,pLight,pDvD;
    }
private:
    Television* pTV;
    Light* pLight;
    DVDplayer* pDvD;
};


int
main(){

    KTVMode* ktv1=new KTVMode;
    ktv1->onKTV();
    delete ktv1;

    return 0;
}

Modo de peso mosca:

        Significa ligero y el chino se traduce como Xiangyuan. Permitir la reutilización idéntica o similar a través de tecnología compartida. Utilice tecnología de uso compartido para respaldar eficazmente la reutilización de una gran cantidad de objetos detallados

ventaja:

    1. Puede reducir el uso de memoria y mejorar el rendimiento del programa. Reduce la cantidad de objetos al compartirlos, reduciendo así la huella de memoria.

    2. Puede mejorar la velocidad de ejecución del programa. Dado que hay menos objetos, hay menos objetos que el programa necesita procesar en tiempo de ejecución, por lo que la velocidad de ejecución del programa será más rápida.

defecto:

    1. El modo Flyweight aumentará la complejidad del programa. Debe separar el estado del objeto en estado interno y estado externo, y considerar cómo compartir el estado interno al implementar objetos de peso mosca.

    2. Puede aumentar el costo de mantenimiento del programa. Dado que el modo flyweight separa la creación y el uso de objetos, es necesario administrar el estado externo en el código del cliente y pasarle el estado externo cuando se utiliza el objeto del modo flyweight. Esto puede aumentar el costo de mantenimiento del programa.

Escena aplicable:

    1. Una aplicación utiliza una gran cantidad de objetos idénticos o similares, lo que provoca una gran sobrecarga de almacenamiento.

    2. La mayor parte del estado del objeto se puede externalizar y estos estados externos se pueden pasar al objeto.

    3. Si elimina el estado externo de un objeto, puede reemplazar muchos grupos de objetos con relativamente pocos objetos compartidos.

    4. La aplicación no se basa en la identificación de objetos. Dado que los objetos Flyweight se pueden compartir, las pruebas de identidad devolverán verdadero para otros objetos conceptualmente obvios.

    5. El uso del modo flyweight requiere mantener un grupo de peso mosca para almacenar objetos de peso mosca, lo que consume recursos. Por lo tanto, vale la pena usar el modo de peso mosca solo cuando el objeto de peso mosca se reutiliza varias veces.

Código de implementación:

#include<iostream>
#include<list>
#include<algorithm>
class ConcreateFlyweight;
class Flyweight{
public:
    virtual ~Flyweight(){}
    std::string GetIntrinsicState(){
        return m_State;
    }
    virtual void Operation(std::string& ExtrinsicState)=0;
protected:
    Flyweight(const std::string& state):m_State(state){}
private:
    std::string m_State;
};

class ConcreateFlyweight:public Flyweight{
public:
    ConcreateFlyweight(const std::string& state):Flyweight(state){}
    virtual ~ConcreateFlyweight(){}
    virtual void Operation(std::string& ExtrinsicState){}
};

class FlyweightFactory{
public:
    FlyweightFactory(){}
    ~FlyweightFactory(){
        for(std::list<Flyweight*>::iterator iter1=m_ListFlyweight.begin(), temp; iter1!=m_ListFlyweight.end(); ){
            temp=iter1;
            ++iter1;
            delete *temp;
        }
        m_ListFlyweight.clear();
    }
    Flyweight* GetFlyweight(const std::string& key){
        for(std::list<Flyweight*>::iterator iter1=m_ListFlyweight.begin(); iter1!=m_ListFlyweight.end(); ++iter1){
            if((*iter1)->GetIntrinsicState() == key){
                std::cout<<"The Flyweight:"<< key<<" already exits " <<std::endl;
                return (*iter1);
            }
        }
        std::cout<<"Creating a new Flyweight:"<<key <<std::endl;
        Flyweight* flyweight =new ConcreateFlyweight(key);
        m_ListFlyweight.push_back(flyweight);
    }
private:
    std::list<Flyweight*> m_ListFlyweight;
};


int
main(){

    FlyweightFactory flyweightfactory;
    flyweightfactory.GetFlyweight("hello");
    flyweightfactory.GetFlyweight("world");
    flyweightfactory.GetFlyweight("hello");

    return 0;
}

Modo agente:

        Proporcionar un proxy para controlar el acceso al objeto original sin cambiar el software

ventaja:

    1. La acusación es clara: el objetivo real se centra en su propia lógica empresarial y no necesita considerar otros contenidos no responsables, dejando que el agente lo complete.

    2. Alta escalabilidad, los cambios en el objeto real no afectan al agente

    3. Desacoplamiento, separando al cliente del objeto real, reduciendo el acoplamiento del sistema.

    4. Mejorar el rendimiento, los agentes virtuales pueden reducir el consumo de recursos del sistema.

    5. Alta seguridad y estabilidad, el agente puede controlar mejor el acceso y mejorar la seguridad del sistema.

defecto:

    1. Incrementar la complejidad del sistema. Los agentes tienen muchas responsabilidades.

    2. La velocidad de solicitud es baja. Agregar servidores proxy al cliente y objetos reales reducirá hasta cierto punto la eficiencia operativa de todo el proceso del sistema.

Escena aplicable:

    Cuando necesite controlar el acceso al objeto original, proporcionar funciones adicionales, reducir la complejidad del código del cliente, etc., puede utilizar el modo proxy

Código de implementación:

#include<iostream>
#include<string>
#include<memory>

class AbstractCommonInterface{
public:
    virtual void run() =0;
};

class MySystem:public AbstractCommonInterface{
public:
    virtual void run(){
        std::cout<<"系统启动"<<std::endl;
    }
};

class MySystemProxy:public AbstractCommonInterface{
public:
    MySystemProxy(std::string username,std::string password){
        mUserName=username;
        mPassWord=password;
        pMySystem=new MySystem;
    }

    bool Check(){
        if(mUserName=="admin" && mPassWord=="admin"){
            return true;
        }
        return false;
    }

    virtual void run(){
        if(Check()==true){
            std::cout<<"启动成功"<<std::endl;
            pMySystem->run();
        }else{
            std::cout<<"用户名或密码错误\n";
        }
    }
    ~MySystemProxy(){
        if(pMySystem !=nullptr){
            delete pMySystem;
        }
    }

private:
    std::string mUserName,mPassWord;
    MySystem* pMySystem;
};


int
main(){

    MySystemProxy* proxy =new MySystemProxy("admin","admin");
    proxy->run();
    return 0;
}

--------------------------Soy una línea divisoria, lo que sigue es el patrón de comportamiento------------ -- ------

Modelo de cadena de responsabilidad:

        ​Crea una cadena de objetos receptores para la solicitud. Este patrón proporciona el tipo de solicitud y desacopla al remitente y al receptor de la solicitud.

ventaja:

    1. Reducir el grado de acoplamiento, que desacopla al remitente y al receptor de la solicitud.

    2. Se mejoró la flexibilidad de asignar responsabilidades a los objetos: al cambiar los miembros dentro de la cadena o mover su orden, permite agregar o eliminar responsabilidades dinámicamente.

    3. Es muy conveniente agregar nuevas clases de procesamiento de solicitudes.

defecto:

    1. No hay garantía de que la solicitud sea procesada porque la solicitud no tiene un destinatario claro.

    2. El rendimiento del sistema se verá afectado hasta cierto punto y será inconveniente al depurar el código, lo que puede provocar llamadas en bucle.

    3. Puede resultar difícil observar las características del tiempo de ejecución, lo que puede provocar errores.

Escena aplicable:

    Por ejemplo, en el mecanismo de manejo de excepciones en Java, cuando un método arroja una excepción, si el método no maneja la excepción internamente, la excepción se pasará al método superior que llama al método para su procesamiento hasta que se maneje o se lance a el programa capa más externa

    Mecanismo de difusión de eventos en JavaScript

    Cadena de filtros en el desarrollo de Servlet.

Código de implementación:

#include<iostream>
#include<algorithm>
#include<vector>
#include<string>

class PurchaseRequest{
public:
    int getType()const{
        return type;
    }
    float getPrice()const{
        return price;
    }
    int getId()const{
        return id;
    }
    PurchaseRequest(const int type,const float price,const int id):type(type),price(price),id(id){

    }
private:
    int type,id;
    float price;
};

class Approver{
public:
    void setApprover(Approver* const approver){
        this->approver=approver;
    }
    explicit Approver(const std::string& name):name(name){}
    virtual void processRequest(PurchaseRequest* purchaseRequest)=0;
protected:
    Approver* approver;
    std::string name;
};

class DepartmentApprover:public Approver{
public:
    explicit DepartmentApprover(const std::string& name):Approver(name){}
    void processRequest(PurchaseRequest* purchaseRequest)override{
        if(purchaseRequest->getPrice()<=5000){
            std::cout<<"请求编号id= "<<purchaseRequest->getId()<<"被"<<this->name<<"处理"<<std::endl;
        }else{
            approver->processRequest(purchaseRequest);
        }
    }
};

class CollegeApprover:public Approver{
public:
    explicit CollegeApprover(const std::string& name):Approver(name){}
    void processRequest(PurchaseRequest* purchaseRequest)override{
        if(purchaseRequest->getPrice()>5000 && purchaseRequest->getPrice()<=10000){
            std::cout<<"请求编号id= "<<purchaseRequest->getId()<<"被"<<this->name<<"处理"<<std::endl;
        }else{
            approver->processRequest(purchaseRequest);
        }
    }
};

class ViceSchoolMasterApprover:public Approver{
public:
    explicit ViceSchoolMasterApprover(const std::string& name):Approver(name){}
    void processRequest(PurchaseRequest* purchaseRequest)override{
        if(purchaseRequest->getPrice()>10000 && purchaseRequest->getPrice()<=30000){
            std::cout<<"请求编号id= "<<purchaseRequest->getId()<<"被"<<this->name<<"处理"<<std::endl;
        }else{
            approver->processRequest(purchaseRequest);
        }
    }
};


int
main(){

    PurchaseRequest* purchaseRequest =new PurchaseRequest(1,10005,1);
    DepartmentApprover* department =new DepartmentApprover("庄主任");
    CollegeApprover* college=new CollegeApprover("李院长");
    ViceSchoolMasterApprover* viceSchoolMaster =new ViceSchoolMasterApprover("王副校长");

    department->setApprover(college);
    college->setApprover(viceSchoolMaster);

    department->processRequest(purchaseRequest);//部长审批不了转交给学院,学院审批不来转交给副校长,副校长能审批批下来了

    return 0;
}

Modo de comando:

        Encapsule una solicitud como un objeto para separar la responsabilidad de realizar la solicitud y la responsabilidad de ejecutarla.

ventaja:

    1. Buena encapsulación, cada comando está encapsulado, para el cliente, si necesita alguna función, puede llamar al comando correspondiente sin saber cómo se ejecuta el comando.

defecto:

    1. Puede provocar que algunos sistemas tengan demasiadas clases de comandos específicas. Debido a que es necesario diseñar una clase de comando específica para cada comando, algunos sistemas pueden requerir una gran cantidad de clases de comando específicas, lo que afectará el uso del modo de comando.

Escena aplicable:

    El sistema necesita desacoplar al solicitante y al receptor de la solicitud para que la persona que llama y el receptor no interactúen directamente

    El sistema necesita especificar solicitudes en diferentes momentos, poner en cola solicitudes y ejecutar solicitudes.

    El sistema necesita admitir las operaciones de deshacer y restaurar de los comandos.

    (El modo de comando se puede utilizar siempre que se consideren comandos)

Código de implementación:

#include<iostream>
#include<vector>
#include<List>
#include<memory>
#include<queue>
#include<windows.h>

class HandleClinetProtocal{
public:
    void AddMoney(){
        std::cout<<"给玩家增加金币"<<std::endl;
    }
    void AddDiamond(){
        std::cout<<"给玩家增加钻石"<<std::endl;
    }
};

class AbstractCommand{
public:
    virtual void handle()=0;
};

class AddMoneyCommand:public AbstractCommand{
public:
    AddMoneyCommand(HandleClinetProtocal* protocal){
        this->pProtocol=protocal;
    }
    virtual void handle(){
        this->pProtocol->AddMoney();
    }
    HandleClinetProtocal* pProtocol;
};

class AddDiamondCommand:public AbstractCommand{
public:
    AddDiamondCommand(HandleClinetProtocal* protocal){
        this->pProtocol=protocal;
    }
    virtual void handle(){
        this->pProtocol->AddMoney();
    }
    HandleClinetProtocal* pProtocol;
};

//服务器程序(命令调用类)
class Server{
public:
    void addRequest(AbstractCommand* command){
        mCommands.push(command);
    }

    //启动处理程序
    void startHandle(){
        while(!mCommands.empty()){
            Sleep(1000);
            AbstractCommand* command =mCommands.front();
            command->handle();
            mCommands.pop();
        }
    }
    std::queue<AbstractCommand*> mCommands;
};


int
main(){

    HandleClinetProtocal* protocal=new HandleClinetProtocal;

    //客户端增加金币的请求
    AbstractCommand* addmoney =new AddMoneyCommand(protocal);

    //客户端增加钻石的请求
    AbstractCommand* adddiamond =new AddDiamondCommand(protocal);

    //将客户端的请求加入到请求队列中
    Server* server =new Server;
    server->addRequest(addmoney);
    server->addRequest(adddiamond);

    //服务器开始处理请求
    server->startHandle();

    return 0;
}

Modo intérprete:

        se refiere a un idioma dado (expresión), definiendo una representación de su gramática y definiendo un intérprete, utilizando al intérprete para interpretar oraciones (expresiones) en el idioma.

ventaja:

    1. Tiene buena escalabilidad. La traducción de gramática se implementa a través de clases y la extensión de las clases puede ampliar sus capacidades de interpretación.

    2. La dificultad de implementación es baja: cada clase de nodo de expresión en el árbol de sintaxis tiene cierta similitud, por lo que es relativamente fácil de implementar.

defecto:

    1. Baja eficiencia de ejecución. Generalmente hay una gran cantidad de bucles y declaraciones recursivas en el intérprete, cuando las oraciones que se interpretan son complejas, el rendimiento del programa se ve muy afectado.

    2. Problema de expansión de clases. Cuando hay más reglas, el número de clases también se expande.

Escena aplicable:

    Cuando un tipo específico de problema ocurre con suficiente frecuencia, por ejemplo, explicación de sintaxis simple, compilador, cálculo de expresiones operativas, expresiones regulares, procesamiento de registros: cuando se utiliza un lenguaje de secuencias de comandos o un lenguaje de programación para procesar registros,

    Se generará una gran cantidad de informes y es necesario analizar los registros y generar informes.

    Los formatos de registro de cada servicio son diferentes, pero los elementos de los datos son los mismos. En este caso, la principal solución para resolver los problemas anteriores a través de programas es utilizar el modo intérprete, que rara vez se utiliza en proyectos diarios.

Compare con el patrón del adaptador: los dos patrones son similares, pero el patrón del adaptador no requiere conocimiento previo de las reglas del adaptador. El modo de intérprete requiere escribir las reglas con anticipación y ejecutar la interpretación de acuerdo con las reglas.

Código de implementación:

#include<iostream>
#include<list>
#include<vector>
#include<algorithm>

class Context{
public:
    Context(int num){
        m_num=num;
    }

    void setNum(int num){
        m_num=num;
    }
    int getNum(){
        return m_num;
    }
    void setRes(int res){
        m_res=res;
    }
    int getRes(){
        return m_res;
    }

private:
    int m_num,m_res;

};

class Expression{
public:
    virtual void interpreter(Context* context) =0;
};

class PlusExpression :public Expression{
public:
    virtual void interpreter(Context* context){
        int num=context->getNum();
        num++;
        context->setNum(num);
        context->setRes(num);
    }
};

class MinusExpression :public Expression{
public:
    virtual void interpreter(Context* context){
        int num =context->getNum();
        num--;
        context->setNum(num);
        context->setRes(num);
    }
};


int
main(){

    Context* pcxt =new Context(10);
    Expression* e1=new PlusExpression();

    e1->interpreter(pcxt);
    std::cout<<"PlusExpression:"<<pcxt->getRes()<<std::endl;

    Expression* e2 =new MinusExpression();
    e2->interpreter(pcxt);
    std::cout<<"MinusExpression:"<<pcxt->getRes()<<std::endl;
    delete e1,e2,pcxt;

    return 0;
}

Patrón de iterador:

        Proporciona una interfaz unificada para atravesar elementos de la colección y utiliza un método coherente para atravesar los elementos de la colección sin conocer la representación subyacente del objeto de la colección. Y cuando necesite atravesar, sin importar cuáles sean estos objetos, debe optar por utilizar el patrón iterador.

ventaja:

    1. Admite atravesar un objeto agregado de diferentes maneras sin exponer su representación interna.

    2. Iterator simplifica las clases agregadas

    3. En el patrón iterador, debido a la introducción de clases abstractas, es muy conveniente agregar nuevas clases agregadas e iteradores sin modificar el código original.

defecto:

    1. Debido a la adición de una capa de abstracción, aumentará la complejidad del sistema.

    2. Para recorridos simples (como matrices), es más engorroso utilizar iteradores para atravesar

Escena aplicable:

    A menudo se utiliza para atravesar varios contenedores, como listas vinculadas, matrices, árboles, etc. En contenedores STL, el patrón iterador se usa ampliamente.

    Todos los contenedores (vector, lista, conjunto) en STL proporcionan iteradores, que se pueden usar para atravesar y acceder a todos los elementos del contenedor.

Código de implementación:

#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
#include<list>

class Iterator{//迭代抽象类,用于定义得到开始对象、得到下一个对象、判断是否到结尾、当前对象等抽象方法,统一接口
public:
    Iterator(){}
    virtual ~Iterator(){}
    virtual std::string First() =0;
    virtual std::string Next() =0;
    virtual std::string CurrentItem() =0;
    virtual bool IsDone() =0;
};

class Aggregate{//聚集抽象类
public:
    virtual int Count() =0;
    virtual void Push(const std::string& strValue) =0;
    virtual std::string Pop(const int nIndex) =0;
    virtual Iterator* CreateIterator() =0;
};

class ConcreteIterator:public Iterator{
public:
    ConcreteIterator(Aggregate* pAggregate):m_nCurrent(0),Iterator(){
        m_Aggregate =pAggregate;
    }
    std::string First(){
        return m_Aggregate->Pop(0);
    }
    std::string Next(){
        std::string strRet;
        m_nCurrent++;
        if(m_nCurrent < m_Aggregate->Count()){
            strRet =m_Aggregate->Pop(m_nCurrent);
        }
        return strRet;
    }
    std::string CurrentItem(){
        return m_Aggregate->Pop(m_nCurrent);
    }
    bool IsDone(){
        return ((m_nCurrent >= m_Aggregate->Count()) ? true :false);
    }
private:
    Aggregate* m_Aggregate;
    int m_nCurrent;
};

class ConcreteAggregate:public Aggregate{
public:
    ConcreteAggregate():m_pIterator(nullptr){
        m_vecItems.clear();
    }
    ~ConcreteAggregate(){
        if(m_pIterator){
            delete m_pIterator;
            m_pIterator=nullptr;
        }
    }
    Iterator* CreateIterator(){
        if(!m_pIterator){
            m_pIterator=new ConcreteIterator(this);
        }
        return m_pIterator;
    }
    int Count(){
        return m_vecItems.size();
    }
    void Push(const std::string& strValue){
        m_vecItems.push_back(strValue);
    }
    std::string Pop(const int nIndex){
        std::string strRet;
        if(nIndex < Count()){
            strRet =m_vecItems[nIndex];
        }
        return strRet;
    }

private:
    std::vector<std::string> m_vecItems;
    Iterator* m_pIterator;
};


int 
main(){

    ConcreteAggregate* pName=new ConcreteAggregate();
    if(pName){
        pName->Push("hello");
        pName->Push("word");
        pName->Push("cxue");
    }
    Iterator* iter =nullptr;
    iter= pName->CreateIterator();
    if(iter){
        std::string strItem =iter->First();
        while(!iter->IsDone()){
            std::cout<< iter->CurrentItem()<<" is ok "<<std::endl;
            iter->Next();
        }
    }
    return 0;
}

Modelo mediador:

        Es un patrón de diseño de software de comportamiento, también conocido como patrón de árbitro. Como sugiere el nombre, la función de este patrón es actuar como intermediario para ayudar a otras clases a comunicarse bien.

ventaja:

    1. Desacoplamiento. La existencia de intermediarios alivia la fuerte relación de acoplamiento entre objetos de compañeros de trabajo. Pueden cambiar de forma independiente sin afectar el conjunto, lo que facilita la reutilización.

    2. Buena escalabilidad. Si el comportamiento de interacción cambia, solo necesita extender la mediación.

    3. Interacción centralizada para una fácil gestión

defecto:

    1. Las responsabilidades del intermediario son muy importantes y complejas.

Escena aplicable:

    Cuando se acoplan varias clases entre sí para formar una estructura de red, es necesario separar la estructura de la red en una estructura en estrella.

Código:

#include<iostream>
#include<string>
#include<memory>
#include<vector>
class Mediator{
public:
    virtual void send(std::string message,Colleague* colleague) =0;
    virtual void add(Colleague* colleague)=0;
};

class Colleague{
public:
    Mediator* getMediator(){
        return mediator;
    }
    void setMediator(Mediator* const mediator){
        this->mediator=mediator;
    }
    Colleague(Mediator* mediator){
        this->mediator =mediator;
        this->mediator->add(this);
    }
    virtual void Notify(std::string message)=0;
private:
    Mediator* mediator;
};

class ConcreteColleague1:public Colleague{
public:
    ConcreteColleague1(Mediator* mediator):Colleague(mediator){}
    void send(std::string message){
        getMediator()->send(message,this);
    }
    void Notify(std::string message){
        std::cout<<"同事1收到信息:"+message<<std::endl;
    }
};

class ConcreteColleague2:public Colleague{
public:
    ConcreteColleague2(Mediator* mediator):Colleague(mediator){}
    void send(std::string message){
        getMediator()->send(message,this);
    }
    void Notify(std::string message){
        std::cout<<"同事2收到信息:"+message<<std::endl;
    }
};

class ConcreteMediator:public Mediator{
public:
    void add(Colleague* colleague){
        colleaguesList.push_back(colleague);
    }
    void send(std::string message,Colleague* colleague){
        for(auto value:colleaguesList){
            if(value!=colleague){
                value->Notify(message);
            }
        }
    }
private:
    std::vector<Colleague*> colleaguesList;
};


int
main(){

    Mediator* mediator =new ConcreteMediator();
    ConcreteColleague1* colleague1 =new ConcreteColleague1(mediator);
    ConcreteColleague2* colleague2 =new ConcreteColleague2(mediator);
    colleague1->send("早上好啊");
    colleague2->send("早安!");


    return 0;
}

Modo nota:

        Capture el estado interno de un objeto y guarde este estado fuera del objeto sin destruir la encapsulación. De esta manera podrás restaurar el objeto a su estado original más adelante.

ventaja:

    1. Cuando cambia el estado del rol del iniciador, puede ser un cambio incorrecto. Podemos usar el modo nota para restaurar este cambio incorrecto.

    2. El estado de la copia de seguridad se guarda fuera del rol del iniciador, de esta manera, el rol del iniciador no necesita administrar el estado de cada copia de seguridad.

defecto:

    1. Si el objeto de respaldo contiene una gran cantidad de información o las operaciones de creación y recuperación son muy frecuentes, puede causar una gran sobrecarga de rendimiento.

Escena aplicable:

    Es necesario guardar el estado de un objeto en un momento determinado para que pueda restaurarse al estado actual cuando sea necesario más adelante.

    Si permite que otros objetos guarden directamente el estado del objeto actual, expondrá los detalles de implementación del objeto y destruirá la encapsulación del objeto.

Código de implementación:

#include<iostream>
#include<list>
#include<memory>
#include<string>
#include<vector>

class Memento{
public:
    explicit Memento(const std::string& state):state(state){}
    std::string getState()const{
        return state;
    }
private:
    std::string state;
};

class Originator{
public:
    std::string getState()const{
        return state;
    }
    void setState(const std::string& state){
        this->state=state;
    }
    Memento SaveStateMemento(){
        return Memento(state);
    }
    void getStateFromMemento(Memento memento){
        state=memento.getState();
    }

private:
    std::string state;
};

class Caretaker{
public:
    void add(Memento memento){
        mementoList.push_back(memento);
    }
    Memento get(int index){
        return mementoList[index];
    }

private:
    std::vector<Memento> mementoList;

};

int
main(){

    Originator originator;
    Caretaker caretaker;
    originator.setState("状态1,攻击力为100");

    //保存当前状态
    caretaker.add(originator.SaveStateMemento());

    //受到debuff,攻击力下降
    originator.setState("状态2,攻击力为80");

    //保存状态
    caretaker.add(originator.SaveStateMemento());

    std::cout<<"当前状态:"<<originator.getState()<<std::endl;
    std::cout<<"debuff状态结束,回到状态1"<<std::endl;
    originator.getStateFromMemento(caretaker.get(0));
    std::cout<<"恢复到状态1后的状态"<<originator.getState();

    return 0;
}

Modo observador:

        Defina relaciones de dependencia de uno a muchos entre objetos. Cuando el estado de un objeto cambia, todos los objetos que dependen de él reciben una notificación y se actualizan automáticamente.

ventaja:

    1. Acoplamiento flexible: el patrón de observador proporciona un diseño de acoplamiento flexible, de modo que cuando el estado de un objeto cambia, no necesita saber cómo otros objetos usan esta información. Sí, el sistema es más fácil de ampliar y mantener.

    2. Asociación dinámica: el patrón de observador permite agregar o eliminar observadores dinámicamente en tiempo de ejecución sin modificar el código del sujeto u otros observadores.

    3. Desacoplamiento abstracto: dado que los sujetos y los observadores se comunican sólo a través de interfaces abstractas, el acoplamiento entre ellos es más abstracto que concreto.

defecto:

    1. Puede provocar actualizaciones inesperadas. Si un observador realiza algunas operaciones después de recibir la notificación y estas operaciones provocan cambios en el estado del tema, puede provocar actualizaciones inesperadas.

    2. Puede causar problemas de rendimiento: si hay una gran cantidad de observadores que deben actualizarse, notificar a todos los observadores puede causar problemas de rendimiento.

    3. Puede aumentar la complejidad. Si no se implementa correctamente, el patrón de observador puede aumentar la complejidad del sistema.

Escena aplicable:

    Cuando el estado de un objeto cambia, es necesario notificar a otros objetos. Cuando el estado de un objeto cambia, es necesario realizar algunas operaciones. Cuando es necesario implementar un diseño débilmente acoplado entre múltiples objetos

Código:

#include<iostream>
#include<string>
#include<memory>
#include<list>

class AbstractHero{//抽象的英雄,抽象的观察者
public:
    virtual void Update() =0;
};

class HeroA :public AbstractHero{//具体的英雄,具体的观察者
public:
    HeroA(){
        std::cout<<"英雄A正在撸BOSS"<<std::endl;
    }
    virtual void Update(){
        std::cout<<"英雄A停止撸,待机状态"<<std::endl;
    }
};

class HeroB :public AbstractHero{
public:
    HeroB(){
        std::cout<<"英雄B正在撸BOSS"<<std::endl;
    }
    virtual void Update(){
        std::cout<<"英雄B停止撸,待机状态"<<std::endl;
    }
};

class AbstractBoss{//定义抽象的观察目标
public:
    virtual void addHero(AbstractHero* hero) =0;//添加观察者
    virtual void deleteHero(AbstractHero* hero)=0;//删除观察者
    virtual void notifv()=0;
};

class BOSSA:public AbstractBoss{
public:
    virtual void addHero(AbstractHero* hero){
        pHeroList.push_back(hero);
    }
    virtual void deleteHero(AbstractHero* hero){
        pHeroList.remove(hero);
    }
    virtual void notifv(){
        for(std::list<AbstractHero*>::iterator it=pHeroList.begin();it!=pHeroList.end();it++){
            (*it)->Update();
        }
    }
    std::list<AbstractHero*> pHeroList;
};


int
main(){

    //创建观察者
    AbstractHero* heroA=new HeroA;
    AbstractHero* heroB=new HeroB;

    //创建观察目标
    AbstractBoss* bossA=new BOSSA;
    bossA->addHero(heroA);
    bossA->addHero(heroB);

    std::cout<<"heroA 阵亡"<<std::endl;
    bossA->deleteHero(heroA);

    std::cout<<"Boss死了,通知其他英雄停止攻击"<<std::endl;
    bossA->notifv();
    delete heroA,heroB,bossA;

    return 0;
}

Modo de estado:

        ​​​Permite que un objeto cambie su comportamiento cuando cambian sus partes internas, de modo que el objeto parece modificar su clase. Puede verse como una extensión de la estrategia. Ambos se basan en mecanismos compositivos.

        Todos cambian su comportamiento en diferentes situaciones delegando parte del trabajo en objetos "ayudantes". La política hace que estos objetos sean completamente independientes entre sí y desconocen su existencia.

        Pero el modelo estatal no limita la dependencia entre estados específicos y les permite cambiar sus estados en diferentes escenarios.

ventaja:

    1. Encapsula las reglas de conversión y también enumera los posibles estados. Antes de enumerar los estados, es necesario confirmar el tipo de estado.

    2. Cumplir con el principio de apertura y cierre. Se pueden introducir nuevos estados sin modificar las clases y contextos de estados existentes.

    3. Simplifique el código de contexto eliminando las declaraciones condicionales infladas de la máquina de estados.

defecto:

    1. Si la máquina de estados tiene solo unos pocos estados o rara vez cambia, aumentará la complejidad del sistema.

    2. El soporte para el "principio de apertura y cierre" no es muy bueno. Para el modo de estado que puede cambiar de estado, agregar una nueva clase de estado requiere modificar el código fuente responsable de la conversión; de lo contrario, no será posible cambiar a el nuevo estado.

Escena aplicable:  

    1. El comportamiento de un objeto depende de su estado y debe cambiar su comportamiento según el estado en tiempo de ejecución.

    2. El código contiene una gran cantidad de declaraciones condicionales relacionadas con el estado del objeto.

Código:

#include<iostream>
#include<string>
#include<memory>
class War;
class State{
public:
    virtual void Prophase(){}
    virtual void Metaphase(){}
    virtual void Anaphase(){}
    virtual void End(){}
    virtual void CurrentState(War* war){}
};

class War{
private:
    State* m_state;//目前状态
    int m_days;//战争持续时间
public:
    War(State* state):m_state(state),m_days(0){}
    ~War(){ delete m_state; }
    int GetDays(){ return m_days; }
    void SetDays(int days){ m_days = days; }
    void SetState(State* state){ delete m_state; m_state = state; }
    void GetState(){ m_state->CurrentState(this); }
};

//战争结束状态
class EndState: public State{
public:
    void End(War* war){
        std::cout<<"战争结束"<<std::endl;
    }
    void CurrentState(War* war){
        End(war);
    }
};

//后期
class AnaphaseState: public State{
public:
    void Anaphase(War* war){//后期具体的行为
        if(war->GetDays() < 30){
            std::cout<<"第"<<war->GetDays()<<"天:战争后期,双方拼死一搏"<<std::endl;
        }else{
            war->SetState(new EndState());
            war->GetState();
        }
    }
    void CurrentState(War* war){ Anaphase(war); }
};


int
main(){

    War* war=new War(new AnaphaseState());
    for(int i=1;i<50;i+=5){
        war->SetDays(i);
        war->GetState();
    }
    return 0;
}

Modo estrategia:

        Cuando el algoritmo está encapsulado, habrá múltiples algoritmos al tratar el problema, es similar al modo Plantilla.

ventaja:

    1. Proporciona un soporte perfecto para el "principio de apertura y cierre". Los usuarios pueden elegir algoritmos o comportamientos sin modificar el código original, y también pueden agregar de manera flexible nuevos algoritmos o comportamientos.

    2. Puede evitar el uso de múltiples juicios condicionales y reducir la dificultad de mantenimiento del programa.

    3. Fuerte escalabilidad

    4. Proporciona un mecanismo de reutilización de algoritmos y diferentes clases de entorno pueden reutilizar fácilmente estas clases de estrategia.

defecto:

    1. Conducirá a un aumento en las clases de estrategia (explosión de clases), lo que dificultará su mantenimiento en el futuro.

    2. Todas las clases de políticas están expuestas al mundo exterior, los permisos del cliente son demasiado grandes y la seguridad es débil.

Escena aplicable:

    1. Si hay muchas clases en un sistema y la única diferencia entre ellas es su comportamiento, el patrón de estrategia se puede utilizar para permitir dinámicamente que un objeto elija entre muchos comportamientos.

    2. Un sistema necesita elegir dinámicamente uno de varios algoritmos.

    3. Si un objeto tiene muchos comportamientos, sin patrones apropiados, estos comportamientos deben implementarse utilizando múltiples declaraciones de selección condicional.

Precauciones:

    Si un sistema tiene más de cuatro estrategias, se debe considerar el uso de un modo híbrido para resolver el problema de la explosión de estrategias.

Código:

#include<iostream>
#include<string>
#include<memory>

class WeaponStrategy{
public:
    virtual void UseWeapon()=0;
};

class Knife :public WeaponStrategy{
public:
    virtual void UseWeapon(){
        std::cout<<"使用匕首"<<std::endl;
    }
};

class AK47 :public WeaponStrategy{
public:
    virtual void UseWeapon(){
        std::cout<<"使用AK47"<<std::endl;
    }
};

class Character{
public:
    WeaponStrategy* pWeapon;
    void setWeapon(WeaponStrategy* pWeapon){
        this->pWeapon=pWeapon;
    }
    void ThrowWeapon(){
        this->pWeapon->UseWeapon();
    }
};

int
main(){

    Character* character=new Character;
    WeaponStrategy* knife=new Knife;
    WeaponStrategy* ak47=new AK47;
    character->setWeapon(ak47);
    character->ThrowWeapon();
    character->setWeapon(knife);
    character->ThrowWeapon();
    delete character,knife,ak47;
    return 0;
}

Modo de plantilla:

        Defina el esqueleto de un algoritmo en una sola operación, difiriendo algunos pasos a subclases. Los métodos de plantilla permiten a las subclases redefinir pasos específicos de un algoritmo sin cambiar la estructura del algoritmo.

ventaja:

    1. Encapsule la parte constante y extienda la parte variable.

    2. Extraer código público para facilitar el mantenimiento.

    3. El comportamiento lo controla la clase principal y lo implementa la subclase (para lograr la reutilización del código)

defecto:

    1. Cada implementación diferente requiere una subclase para implementar, lo que resulta en un aumento en el número de clases y hace que el sistema sea más grande.

Escena aplicable:

        Para una determinada lógica empresarial, existen diferentes implementaciones detalladas en diferentes objetos, pero el marco lógico es el mismo.

Código:

#include<iostream>
#include<algorithm>
#include<string>

class DrinkTemplate{//做饮料模板
public:
    virtual void BoildWater()=0;
    virtual void Brew()=0;
    virtual void PourInCup()=0;
    virtual void AddSomething()=0;
    void Make(){
        BoildWater();
        Brew();
        PourInCup();
        AddSomething();
    }
};

class Coffee :public DrinkTemplate{
    virtual void BoildWater(){
        std::cout<<"煮山泉水"<<std::endl;
    }
    virtual void Brew(){
        std::cout<<"冲泡咖啡"<<std::endl;
    }
    virtual void PourInCup(){
        std::cout<<"咖啡加入杯中"<<std::endl;
    }
    virtual void AddSomething(){
        std::cout<<"加糖加牛奶"<<std::endl;
    }
};

class Tea :public DrinkTemplate{
    virtual void BoildWater(){
        std::cout<<"煮自来水"<<std::endl;
    }
    virtual void Brew(){
        std::cout<<"冲泡铁观音"<<std::endl;
    }
    virtual void PourInCup(){
        std::cout<<"茶水加入杯中"<<std::endl;
    }
    virtual void AddSomething(){
        std::cout<<"加下雨天氛围"<<std::endl;
    }
};

int
main(){

    Tea* tea = new Tea;
    tea->Make();
    Coffee* coffee=new Coffee;
    coffee->Make();

    return 0;
}

Modo visitante:

        Encapsula algunas operaciones que actúan sobre cada elemento de una determinada estructura de datos y puede definir nuevas operaciones que actúan sobre estos elementos sin cambiar la estructura de datos.

ventaja:

    1. Buena escalabilidad. Para ampliar las operaciones sobre elementos, simplemente agregue visitantes

    2. Cumplir con el principio de responsabilidad única. Las operaciones relacionadas se encapsulan en un visitante, lo que hace que el visitante sea responsable de un único

    3. Desacoplar, desacoplar la propia estructura de datos y las operaciones que actúan sobre ella.

defecto:

    1. No es fácil agregar categorías. Cada vez que se agrega una clase de elemento, la interfaz del visitante y la implementación deben cambiar.

    2. Viola el principio de inversión de dependencia: los visitantes proporcionan elementos específicos en lugar de elementos abstractos.

    3. Destruir la encapsulación. Los visitantes pueden obtener detalles del elemento visitado.

Escena aplicable:

        Es adecuado para sistemas donde la estructura de datos es relativamente estable y el algoritmo es fácil de cambiar.

Código:

#include<iostream>
#include<algorithm>
#include<string>
#include<queue>
#include<List>
class Man;
class Woman;

class Action{
public:
    virtual void getManResult(Man* man) =0;
    virtual void getWomanResult(Woman* woman) =0;
};

class Success:public Action{
public:
    void getManResult(Man* man) override{
        std::cout<<"男人的给的评价该歌手是很成功"<<std::endl;
    }
    void getWomanResult(Woman* woman) override{
        std::cout<<"女人给的评价是该歌手很成功"<<std::endl;
    }
};

class Fail:public Action{
public:
    void getManResult(Man* man) override{
        std::cout<<"男人的给的评价该歌手是很失败"<<std::endl;
    }
    void getWomanResult(Woman* woman) override{
        std::cout<<"女人给的评价是该歌手很失败"<<std::endl;
    }
};

class Person{
public:
    virtual void accept(Action* action) =0;
};

class Man:public Person{
public:
    void accept(Action* action)override{
        action->getManResult(this);
    }
};

class Woman:public Person{
public:
    void accept(Action* action)override{
        action->getWomanResult(this);
    }
};

class ObjectStructure{
public:
    void attach(Person* p){
        persons.push_back(p);
    }
    void detach(Person* p){
        persons.remove(p);
        delete p;
    }
    //显示测评情况
    void display(Action* action){
        for(auto value:persons){
            value->accept(action);
        }
    }

private:
    std::list<Person*> persons;
};


int
main(){

    ObjectStructure* objectStructure =new ObjectStructure;
    objectStructure->attach(new Man);
    objectStructure->attach(new Woman);


    return 0;
}

referencia:

Patrones de diseño de C ++ (23 tipos en total)_blog-CSDN de blog de momohola

Varios patrones de diseño comunes en C ++_c ++ patrones de diseño_blog-CSDN de blog de lTimej

11 patrones de diseño comúnmente utilizados en el diseño de C++_c++ model_CBoy_JW's blog-CSDN blog

Patrón de diseño de gran charla

c ++ efectivo

"Patrones de diseño de C++"_Patrones de diseño de C++_Blog de Yiqou Ersanli-Blog CSDN

blog de txinyu_-blog de CSDN

Supongo que te gusta

Origin blog.csdn.net/songbijian/article/details/132656594
Recomendado
Clasificación