23种设计模式笔记-结构型模式

23种设计模式-结构型模式

笔记模板

模式

  • 前提 - 模式:
  • 概念:
  • 规则:
  • 实现细节:
  • 应用场景:
  • 示意图:
  • 代码实现:

创建型模式

  • 适配器、桥接、组合、装饰、外观、享元、代理。

适配器模式 - 接口兼容思想

  • 概念: 将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作(核心:适配器)

  • 规则: 通过一个类,实现从调用者(客户端)到被调用者(服务端)的接口实现

  • 实现细节: 其分为对象适配器和类适配器,对象适配器其功能为接口的转换(一对一,即单一继承),类适配器为多重继承,即继承了不同类的产物,可以更好的封装适配器(多对多,即多重继承)
    客户端接口 ---适配器--- 服务端实现;
    实现时需要注意,使用构造函数/调用方法传递的方式实现服务对象的引用;
    实现方法以客户端接口为准,即使用服务端实现完成对客户端接口的适配

  • 应用场景: 1.使用类,但是其接口与其他代码不兼容;2.复用属于同一个继承体系,但是存在额外共性的类。这些额外共性可以使用适配器实现(类似于装饰器);操作系统本质就是一种适配器,按其标准实现了对硬件的封装,从而使上层的软件能够以标准接口,如POSIX等,实现对其的调用。

  • 示意图:
    对象适配器:
    image
    类适配器
    image

  • 代码实现:

    c++
    //对象适配器
    /**
     * The Target defines the domain-specific interface used by the client code.
     */
    class Target {
     public:
      virtual ~Target() = default;
    
      virtual std::string Request() const {
    	return "Target: The default target's behavior.";
      }
    };
    
    /**
     * The Adaptee contains some useful behavior, but its interface is incompatible
     * with the existing client code. The Adaptee needs some adaptation before the
     * client code can use it.
     */
    class Adaptee {
     public:
      std::string SpecificRequest() const {
    	return ".eetpadA eht fo roivaheb laicepS";
      }
    };
    
    /**
     * The Adapter makes the Adaptee's interface compatible with the Target's
     * interface.
     */
    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;
      }
    };
    
    /**
     * The client code supports all classes that follow the Target interface.
     */
    void ClientCode(const Target *target) {
      std::cout << target->Request();
    }
    
    int main() {
      std::cout << "Client: I can work just fine with the Target objects:\n";
      Target *target = new Target;
      ClientCode(target);
      std::cout << "\n\n";
      Adaptee *adaptee = new Adaptee;
      std::cout << "Client: The Adaptee class has a weird interface. See, I don't understand it:\n";
      std::cout << "Adaptee: " << adaptee->SpecificRequest();
      std::cout << "\n\n";
      std::cout << "Client: But I can work with it via the Adapter:\n";
      Adapter *adapter = new Adapter(adaptee);
      ClientCode(adapter);
      std::cout << "\n";
    
      delete target;
      delete adaptee;
      delete adapter;
    
      return 0;
    }
    
    //多重继承
    /**
     * The Target defines the domain-specific interface used by the client code.
     */
    class Target {
     public:
      virtual ~Target() = default;
      virtual std::string Request() const {
    	return "Target: The default target's behavior.";
      }
    };
    
    /**
     * The Adaptee contains some useful behavior, but its interface is incompatible
     * with the existing client code. The Adaptee needs some adaptation before the
     * client code can use it.
     */
    class Adaptee {
     public:
      std::string SpecificRequest() const {
    	return ".eetpadA eht fo roivaheb laicepS";
      }
    };
    
    /**
     * The Adapter makes the Adaptee's interface compatible with the Target's
     * interface using multiple inheritance.
     */
    class Adapter : public Target, public Adaptee {
     public:
      Adapter() {}
      std::string Request() const override {
    	std::string to_reverse = SpecificRequest();
    	std::reverse(to_reverse.begin(), to_reverse.end());
    	return "Adapter: (TRANSLATED) " + to_reverse;
      }
    };
    
    /**
     * The client code supports all classes that follow the Target interface.
     */
    void ClientCode(const Target *target) {
      std::cout << target->Request();
    }
    
    int main() {
      std::cout << "Client: I can work just fine with the Target objects:\n";
      Target *target = new Target;
      ClientCode(target);
      std::cout << "\n\n";
      Adaptee *adaptee = new Adaptee;
      std::cout << "Client: The Adaptee class has a weird interface. See, I don't understand it:\n";
      std::cout << "Adaptee: " << adaptee->SpecificRequest();
      std::cout << "\n\n";
      std::cout << "Client: But I can work with it via the Adapter:\n";
      Adapter *adapter = new Adapter;
      ClientCode(adapter);
      std::cout << "\n";
    
      delete target;
      delete adaptee;
      delete adapter;
    
      return 0;
    }
    
    c
    #include <stdio.h>
    #include <stdlib.h>
    
    // 定义适配者接口
    struct adaptee {
    	void (*specificRequest)(void);
    };
    
    // 适配者操作
    void adaptee_specificRequest(void)
    {
    	printf("adaptee specific request\n");
    }
    
    // 初始化适配者
    struct adaptee* adaptee_create(void)
    {
    	struct adaptee* adaptee = (struct adaptee *)malloc(sizeof(struct adaptee *));
    	adaptee->specificRequest = adaptee_specificRequest;
    	return adaptee;
    }
    
    typedef struct adapter adapter;
    
    // 定义目标接口
    struct target {
    	void (*request)(struct adapter* this);
    };
    
    // 定义适配器
    struct adapter {
    	struct adaptee* adaptee;
    	struct target target;
    };
    
    // 适配器请求操作
    void adapter_request(struct adapter* this)
    {
    	printf("adapter request\n");
    	this->adaptee->specificRequest();
    }
    
    // 初始化适配器
    struct adapter* adapter_create(struct adaptee* adaptee)
    {
    	struct adapter* adapter = (struct adapter *)malloc(sizeof(struct adapter *));
    	adapter->target.request = (void (*)())adapter_request;
    	adapter->adaptee = adaptee;
    	return adapter;
    }
    
    int main() {
    	// 创建适配者
    	struct adaptee* adaptee = adaptee_create();
    
    	// 创建适配器,并使用适配者初始化
    	struct adapter* adapter = adapter_create(adaptee);
    
    	// 调用适配器的请求方法
    	adapter->target.request(adapter);
    
    	// 释放内存
    	free(adapter);
    	free(adaptee);
    
    	return 0;
    }
    

桥接模式 - 对复杂系统的分离

  • 前提 - 抽象工厂模式、适配器模式: 桥接模式中的抽象方/实现方的实现可以使用抽象工厂模式,适配器可以对特定的实现

  • 概念: 将抽象部分与它的实现部分分离,使它们都可以独立地变化。(核心是避免子类数量的爆炸)

  • 规则: 使用组合的方式,实现对类之间的自由组合,从而降低了子类的数量(适用于开发过程中的实现),核心是降低耦合度

  • 实现细节: 抽象部分(GUI)其实现了控制程序的外观、实现部分(API)采用标准的API,实现了对多种操作系统的适配、而GUI和API之间使用了桥接模式进行适配;UNIX标准输入输出,如POSIX就是作为一个桥接器存在的。LINUX的各种子系统类似于这个关系,其充当了硬件实现(驱动)和软件抽象(API)的桥接
    核心是在设计之前解耦维度,实现维度的独立性;同时,实现多层次的抽象

  • 应用场景:1.拆分或者重组复杂类(对复杂代码进行解耦);2.在多个维度上对原有类进行扩展;3.需要在运行时切换不同的实现方法

  • 示意图:
    image

  • 代码实现:

    c++
    /**
     * The Implementation defines the interface for all implementation classes. It
     * doesn't have to match the Abstraction's interface. In fact, the two
     * interfaces can be entirely different. Typically the Implementation interface
     * provides only primitive operations, while the Abstraction defines higher-
     * level operations based on those primitives.
     */
    
    class Implementation {
     public:
      virtual ~Implementation() {}
      virtual std::string OperationImplementation() const = 0;
    };
    
    /**
     * Each Concrete Implementation corresponds to a specific platform and
     * implements the Implementation interface using that platform's API.
     */
    class ConcreteImplementationA : public Implementation {
     public:
      std::string OperationImplementation() const override {
    	return "ConcreteImplementationA: Here's the result on the platform A.\n";
      }
    };
    class ConcreteImplementationB : public Implementation {
     public:
      std::string OperationImplementation() const override {
    	return "ConcreteImplementationB: Here's the result on the platform B.\n";
      }
    };
    
    /**
     * The Abstraction defines the interface for the "control" part of the two class
     * hierarchies. It maintains a reference to an object of the Implementation
     * hierarchy and delegates all of the real work to this object.
     */
    
    class Abstraction {
      /**
       * @var Implementation
       */
     protected:
      Implementation* implementation_;
    
     public:
      Abstraction(Implementation* implementation) : implementation_(implementation) {
      }
    
      virtual ~Abstraction() {
      }
    
      virtual std::string Operation() const {
    	return "Abstraction: Base operation with:\n" +
    		   this->implementation_->OperationImplementation();
      }
    };
    /**
     * You can extend the Abstraction without changing the Implementation classes.
     */
    class ExtendedAbstraction : public Abstraction {
     public:
      ExtendedAbstraction(Implementation* implementation) : Abstraction(implementation) {
      }
      std::string Operation() const override {
    	return "ExtendedAbstraction: Extended operation with:\n" +
    		   this->implementation_->OperationImplementation();
      }
    };
    
    /**
     * Except for the initialization phase, where an Abstraction object gets linked
     * with a specific Implementation object, the client code should only depend on
     * the Abstraction class. This way the client code can support any abstraction-
     * implementation combination.
     */
    void ClientCode(const Abstraction& abstraction) {
      // ...
      std::cout << abstraction.Operation();
      // ...
    }
    /**
     * The client code should be able to work with any pre-configured abstraction-
     * implementation combination.
     */
    
    int main() {
      Implementation* implementation = new ConcreteImplementationA;
      Abstraction* abstraction = new Abstraction(implementation);
      ClientCode(*abstraction);
      std::cout << std::endl;
      delete implementation;
      delete abstraction;
    
      implementation = new ConcreteImplementationB;
      abstraction = new ExtendedAbstraction(implementation);
      ClientCode(*abstraction);
    
      delete implementation;
      delete abstraction;
    
      return 0;
    }
    
    c
    #include <stdio.h>
    
    // 实现方接口
    typedef struct {
    	void (*implement)(void);
    } Implementation;
    
    // 具体实现类A
    void implementA(void) {
    	printf("Implementation A method\n");
    }
    
    // 具体实现类B
    void implementB(void) {
    	printf("Implementation B method\n");
    }
    
    // 抽象方接口
    typedef struct {
    	void (*abstractionOperation)(void);
    	Implementation *implementation;
    } Abstraction;
    
    // 抽象方实现A
    void abstractionAMethod(Abstraction *abstraction) {
    	printf("Abstraction A method\n");
    	abstraction->implementation->implement();
    }
    
    // 抽象方实现B
    void abstractionBMethod(Abstraction *abstraction) {
    	printf("Abstraction B method\n");
    	abstraction->implementation->implement();
    }
    
    int main() {
    	Implementation implementationA = {implementA};
    	Implementation implementationB = {implementB};
    
    	Abstraction abstractionA = {abstractionAMethod, &implementationA};
    	Abstraction abstractionB = {abstractionBMethod, &implementationB};
    
    	abstractionA.abstractionOperation(&abstractionA);
    	abstractionB.abstractionOperation(&abstractionB);
    
    	return 0;
    }
    

组合模式 - 树形的层级结构,降低系统的复杂度

  • 概念: 将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性

  • 规则: 对与产品-盒子交互策略来说,需要设计一个通用接口逐级实现所需要功能,其核心思想是降低耦合度,即上层只需要调用相应接口,下层递归实现即可

  • 实现细节: 对于每个产品(叶子节点)而言,其实现了对应的工作(最简单的工作);而对于盒子(子根结点)而言,其作用是对操作进行分发与组合,以实现产品的结合;而对于组件(通用接口)而言,其需要实现对于操作(方法)的抽象,从而提供给产品和盒子。该种模式应用与前端显示组件的编写上,如LVGL、AWTK等,其在绘制时,使用了树形结构进行逐层调用与绘制

  • 应用场景: 实现树状对象结构;客户端能够以相同方式处理简单和复杂元素

  • 示意图:
    image

  • 代码实现:

    c++
    #include <algorithm>
    #include <iostream>
    #include <list>
    #include <string>
    /**
     * The base Component class declares common operations for both simple and
     * complex objects of a composition.
     */
    class Component {
      /**
       * @var Component
       */
     protected:
      Component *parent_;
      /**
       * Optionally, the base Component can declare an interface for setting and
       * accessing a parent of the component in a tree structure. It can also
       * provide some default implementation for these methods.
       */
     public:
      virtual ~Component() {}
      void SetParent(Component *parent) {
    	this->parent_ = parent;
      }
      Component *GetParent() const {
    	return this->parent_;
      }
      /**
       * In some cases, it would be beneficial to define the child-management
       * operations right in the base Component class. This way, you won't need to
       * expose any concrete component classes to the client code, even during the
       * object tree assembly. The downside is that these methods will be empty for
       * the leaf-level components.
       */
      virtual void Add(Component *component) {}
      virtual void Remove(Component *component) {}
      /**
       * You can provide a method that lets the client code figure out whether a
       * component can bear children.
       */
      virtual bool IsComposite() const {
    	return false;
      }
      /**
       * The base Component may implement some default behavior or leave it to
       * concrete classes (by declaring the method containing the behavior as
       * "abstract").
       */
      virtual std::string Operation() const = 0;
    };
    /**
     * The Leaf class represents the end objects of a composition. A leaf can't have
     * any children.
     *
     * Usually, it's the Leaf objects that do the actual work, whereas Composite
     * objects only delegate to their sub-components.
     */
    class Leaf : public Component {
     public:
      std::string Operation() const override {
    	return "Leaf";
      }
    };
    /**
     * The Composite class represents the complex components that may have children.
     * Usually, the Composite objects delegate the actual work to their children and
     * then "sum-up" the result.
     */
    class Composite : public Component {
      /**
       * @var \SplObjectStorage
       */
     protected:
      std::list<Component *> children_;
    
     public:
      /**
       * A composite object can add or remove other components (both simple or
       * complex) to or from its child list.
       */
      void Add(Component *component) override {
    	this->children_.push_back(component);
    	component->SetParent(this);
      }
      /**
       * Have in mind that this method removes the pointer to the list but doesn't
       * frees the
       *     memory, you should do it manually or better use smart pointers.
       */
      void Remove(Component *component) override {
    	children_.remove(component);
    	component->SetParent(nullptr);
      }
      bool IsComposite() const override {
    	return true;
      }
      /**
       * The Composite executes its primary logic in a particular way. It traverses
       * recursively through all its children, collecting and summing their results.
       * Since the composite's children pass these calls to their children and so
       * forth, the whole object tree is traversed as a result.
       */
      std::string Operation() const override {
    	std::string result;
    	for (const Component *c : children_) {
    	  if (c == children_.back()) {
    		result += c->Operation();
    	  } else {
    		result += c->Operation() + "+";
    	  }
    	}
    	return "Branch(" + result + ")";
      }
    };
    /**
     * The client code works with all of the components via the base interface.
     */
    void ClientCode(Component *component) {
      // ...
      std::cout << "RESULT: " << component->Operation();
      // ...
    }
    
    /**
     * Thanks to the fact that the child-management operations are declared in the
     * base Component class, the client code can work with any component, simple or
     * complex, without depending on their concrete classes.
     */
    void ClientCode2(Component *component1, Component *component2) {
      // ...
      if (component1->IsComposite()) {
    	component1->Add(component2);
      }
      std::cout << "RESULT: " << component1->Operation();
      // ...
    }
    
    /**
     * This way the client code can support the simple leaf components...
     */
    
    int main() {
      Component *simple = new Leaf;
      std::cout << "Client: I've got a simple component:\n";
      ClientCode(simple);
      std::cout << "\n\n";
      /**
       * ...as well as the complex composites.
       */
    
      Component *tree = new Composite;
      Component *branch1 = new Composite;
    
      Component *leaf_1 = new Leaf;
      Component *leaf_2 = new Leaf;
      Component *leaf_3 = new Leaf;
      branch1->Add(leaf_1);
      branch1->Add(leaf_2);
      Component *branch2 = new Composite;
      branch2->Add(leaf_3);
      tree->Add(branch1);
      tree->Add(branch2);
      std::cout << "Client: Now I've got a composite tree:\n";
      ClientCode(tree);
      std::cout << "\n\n";
    
      std::cout << "Client: I don't need to check the components classes even when managing the tree:\n";
      ClientCode2(tree, simple);
      std::cout << "\n";
    
      delete simple;
      delete tree;
      delete branch1;
      delete branch2;
      delete leaf_1;
      delete leaf_2;
      delete leaf_3;
    
      return 0;
    }
    
    c
    #include <stdio.h>
    #include <stdlib.h>
    
    enum type{
    	LEAF = 1,
    	BRANCH,
    };
    // 定义组件接口
    typedef struct Component {
    	int value;
    	int type;
    	void (*operation)(struct Component *);
    } Component;
    
    // 定义叶子节点
    typedef struct Leaf {
    	Component base;
    } Leaf;
    
    void leaf_operation(Component *component) {
    	printf("Leaf: %d\n", component->value);
    }
    
    Leaf* leaf_create(int value) {
    	Leaf *leaf = (Leaf*)malloc(sizeof(Leaf));
    	leaf->base.value = value;
    	leaf->base.type = LEAF;
    	leaf->base.operation = leaf_operation;
    	return leaf;
    }
    
    // 定义组合节点
    typedef struct Composite {
    	Component base;
    	Component **children;
    	int num_children;
    } Composite;
    
    #define offsetof(s, m)      ((size_t)&(((s *)0)->m))
    #define container_of(ptr, type, member) \
    	((type *)((char *)(ptr) - offsetof(type, member)))
    
    void composite_operation(Component *component) {
    	Composite *composite = (Composite*)component;
    	printf("Composite: %d\n", component->value);
    
    	for (int i = 0; i < composite->num_children; i++) {
    		composite->children[i]->operation(composite->children[i]);
    	}
    }
    
    Composite* composite_create(int value, int num_children) {
    	Composite *composite = (Composite*)malloc(sizeof(Composite));
    	composite->base.value = value;
    	composite->base.type = BRANCH;
    	composite->base.operation = composite_operation;
    	composite->num_children = num_children;
    	composite->children = (Component**)malloc(sizeof(Component*) * num_children);
    	for (int i = 0; i < num_children; i++) {
    		composite->children[i] = NULL;
    	}
    	return composite;
    }
    
    void composite_add_child(Composite *composite, Component *child, int index) {
    	if (index < 0 || index >= composite->num_children) {
    		printf("Invalid index %d\n", index);
    		return;
    	}
    	composite->children[index] = child;
    }
    
    void composite_remove_child(Composite *composite, int index) {
    	if (index < 0 || index >= composite->num_children) {
    		printf("Invalid index %d\n", index);
    		return;
    	}
    	composite->children[index] = NULL;
    }
    
    void composite_free_unit(Composite *composite) {
    	if (!composite)
    		return;
    
    	if (composite->base.type == LEAF)
    		return;
    
    	for (int i = 0; i < composite->num_children; i++) {
    		if (composite->children[i]) {
    		composite_free_unit((struct Composite*)container_of(composite->children[i], struct Composite, base));
    		printf("free children[%d], value: %d\n", i, composite->children[i]->value);
    			free(composite->children[i]);
    		}
    	}
    
    	if (composite->children) {
    		free(composite->children);
    	}
    }
    
    void composite_free(Composite *composite) {
    	composite_free_unit(composite);
    	if (composite) {
    		free(composite);
    	}
    }
    int main() {
    	printf("create root and leaf\n");
    	// 创建根节点和叶子节点
    	Composite *root = composite_create(0, 3);
    	Leaf *leaf1 = leaf_create(1);
    	Leaf *leaf2 = leaf_create(2);
    
    	// 将叶子节点添加到根节点中
    	composite_add_child(root, &leaf1->base, 0);
    	composite_add_child(root, &leaf2->base, 1);
    
    	// 创建子节点并将其添加到根节点中
    	Composite *subtree = composite_create(3, 2);
    	Leaf *leaf3 = leaf_create(4);
    	Leaf *leaf4 = leaf_create(5);
    	composite_add_child(subtree, &leaf3->base, 0);
    	composite_add_child(subtree, &leaf4->base, 1);
    	composite_add_child(root, &subtree->base, 2);
    
    	// 执行操作
    	root->base.operation(&root->base);
    
    	printf("free root and leaf\n");
    	// 释放内存
    	composite_free(root);
    
    	return 0;
    }
    

装饰器模式 - 使对象和方法解耦,是桥接模式的另一种实现

  • 概念: 动态地给一个对象添加一些额外的职责。就增加功能来说,相比生成子类更为灵活;

  • 规则: 核心需求是防止需求的增加导致子类数量的爆炸;其核心方法是利用聚合/组合思想,实现封装器,而不是使用继承。封装器需要实现与封装对象相同的接口,从而使客户端可以对采用同一接口进行调用

  • 实现细节: 在客户端,客户需要将基础对象放入一系列装饰中,形成栈结构;在装饰器中,需要实现装饰基类以实现基础接口,同时,实现具体装饰类实现装饰所需的操作

  • 应用场景: 无需修改原始代码的情况下使用对象,并为对象添加额外的方法(行为);面向对象方法的扩展受到无法(难以)继承的限制;

  • 示意图:
    image

  • 代码实现:

    c++
    /**
     * The base Component interface defines operations that can be altered by
     * decorators.
     */
    class Component {
     public:
      virtual ~Component() {}
      virtual std::string Operation() const = 0;
    };
    /**
     * Concrete Components provide default implementations of the operations. There
     * might be several variations of these classes.
     */
    class ConcreteComponent : public Component {
     public:
      std::string Operation() const override {
    	return "ConcreteComponent";
      }
    };
    /**
     * The base Decorator class follows the same interface as the other components.
     * The primary purpose of this class is to define the wrapping interface for all
     * concrete decorators. The default implementation of the wrapping code might
     * include a field for storing a wrapped component and the means to initialize
     * it.
     */
    class Decorator : public Component {
      /**
       * @var Component
       */
     protected:
      Component* component_;
    
     public:
      Decorator(Component* component) : component_(component) {
      }
      /**
       * The Decorator delegates all work to the wrapped component.
       */
      std::string Operation() const override {
    	return this->component_->Operation();
      }
    };
    /**
     * Concrete Decorators call the wrapped object and alter its result in some way.
     */
    class ConcreteDecoratorA : public Decorator {
      /**
       * Decorators may call parent implementation of the operation, instead of
       * calling the wrapped object directly. This approach simplifies extension of
       * decorator classes.
       */
     public:
      ConcreteDecoratorA(Component* component) : Decorator(component) {
      }
      std::string Operation() const override {
    	return "ConcreteDecoratorA(" + Decorator::Operation() + ")";
      }
    };
    /**
     * Decorators can execute their behavior either before or after the call to a
     * wrapped object.
     */
    class ConcreteDecoratorB : public Decorator {
     public:
      ConcreteDecoratorB(Component* component) : Decorator(component) {
      }
    
      std::string Operation() const override {
    	return "ConcreteDecoratorB(" + Decorator::Operation() + ")";
      }
    };
    /**
     * The client code works with all objects using the Component interface. This
     * way it can stay independent of the concrete classes of components it works
     * with.
     */
    void ClientCode(Component* component) {
      // ...
      std::cout << "RESULT: " << component->Operation();
      // ...
    }
    
    int main() {
      /**
       * This way the client code can support both simple components...
       */
      Component* simple = new ConcreteComponent;
      std::cout << "Client: I've got a simple component:\n";
      ClientCode(simple);
      std::cout << "\n\n";
      /**
       * ...as well as decorated ones.
       *
       * Note how decorators can wrap not only simple components but the other
       * decorators as well.
       */
      Component* decorator1 = new ConcreteDecoratorA(simple);
      Component* decorator2 = new ConcreteDecoratorB(decorator1);
      std::cout << "Client: Now I've got a decorated component:\n";
      ClientCode(decorator2);
      std::cout << "\n";
    
      delete simple;
      delete decorator1;
      delete decorator2;
    
      return 0;
    }
    
    c
    #include <stdio.h>
    #include <stdlib.h>
    
    // 被装饰者抽象接口Component
    typedef struct Component {
    	void (*operation)(struct Component *);
    } Component;
    
    // 被装饰者具体实现ConcreteComponent
    typedef struct ConcreteComponent {
    	Component base;
    } ConcreteComponent;
    
    // 具体的被装饰者实现的操作
    void concrete_operation(Component *self) {
    	printf("Concrete operation\n");
    }
    
    // 装饰者基类
    typedef struct Decorator {
    	Component base;
    	Component *decorated;
    } Decorator;
    
    // 装饰者的操作实现
    void decorator_operation(Component *self) {
    	Decorator *decorator = (Decorator *)self;
    	decorator->decorated->operation(decorator->decorated);
    }
    
    // 具体的装饰者A实现
    typedef struct ConcreteDecoratorA {
    	Decorator base;
    } ConcreteDecoratorA;
    
    // 装饰者A装饰的功能实现
    void decorator_a_operation(Component *self)
    {
    	printf("Excuting decoratorA operation.\n");
    
    	//调用父类方法
    	decorator_operation(self);
    }
    
    // 具体的装饰者B实现
    typedef struct ConcreteDecoratorB {
    	Decorator base;
    } ConcreteDecoratorB;
    
    // 装饰者B装饰的功能实现
    void decorator_b_operation(Component *self)
    {
    	printf("Excuting decoratorB operation.\n");
    
    	//调用父类方法
    	decorator_operation(self);
    }
    
    int main() {
    	// 创建被装饰者
    	ConcreteComponent component = { {concrete_operation} };
    
    	// 创建具体的装饰者A
    	ConcreteDecoratorA a = {
    								{
    									{ decorator_a_operation },
    									(Component *)&component
    								}
    							};
    
    	// 创建具体的装饰者B
    	ConcreteDecoratorB b = {
    								{
    									{ decorator_b_operation },
    									(Component *)&component
    								}
    							};
    
    	// 调用装饰者A的功能
    	Component *componenta = (Component *)&a;
    	componenta->operation(componenta);
    
    	// 调用装饰者B的功能
    	Component *componentb = (Component *)&b;
    	componentb->operation(componentb);
    
    	return 0;
    }
    

外观模式- 通过封装相应操作,简化客户端操作

  • 概念: 为子系统中的一组接口提供一个一致的界面。外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用

  • 规则: 其核心是将复杂接口包装起来,对外提供一个实现具体功能的接口。即通过需求出发,创建相应的外观类

  • 实现细节: 根据所客户端常见的需求,对背后的复杂系统进行封装,从而实现应用程序的调用;实现的时候需要适当选择,避免其成为上帝对象(和所有类都耦合)

  • 应用场景:需要一个指向复杂子系统的直接接口(常用功能的快捷方式);将子系统组织为多层结构。操作系统的各种操作(syscall)可以理解为外观模式的应用。

  • 示意图:
    image

  • 代码实现:

    c++
    /**
     * The Subsystem can accept requests either from the facade or client directly.
     * In any case, to the Subsystem, the Facade is yet another client, and it's not
     * a part of the Subsystem.
     */
    class Subsystem1 {
     public:
      std::string Operation1() const {
    	return "Subsystem1: Ready!\n";
      }
      // ...
      std::string OperationN() const {
    	return "Subsystem1: Go!\n";
      }
    };
    /**
     * Some facades can work with multiple subsystems at the same time.
     */
    class Subsystem2 {
     public:
      std::string Operation1() const {
    	return "Subsystem2: Get ready!\n";
      }
      // ...
      std::string OperationZ() const {
    	return "Subsystem2: Fire!\n";
      }
    };
    
    /**
     * The Facade class provides a simple interface to the complex logic of one or
     * several subsystems. The Facade delegates the client requests to the
     * appropriate objects within the subsystem. The Facade is also responsible for
     * managing their lifecycle. All of this shields the client from the undesired
     * complexity of the subsystem.
     */
    class Facade {
     protected:
      Subsystem1 *subsystem1_;
      Subsystem2 *subsystem2_;
      /**
       * Depending on your application's needs, you can provide the Facade with
       * existing subsystem objects or force the Facade to create them on its own.
       */
     public:
      /**
       * In this case we will delegate the memory ownership to Facade Class
       */
      Facade(
    	  Subsystem1 *subsystem1 = nullptr,
    	  Subsystem2 *subsystem2 = nullptr) {
    	this->subsystem1_ = subsystem1 ?: new Subsystem1;
    	this->subsystem2_ = subsystem2 ?: new Subsystem2;
      }
      ~Facade() {
    	delete subsystem1_;
    	delete subsystem2_;
      }
      /**
       * The Facade's methods are convenient shortcuts to the sophisticated
       * functionality of the subsystems. However, clients get only to a fraction of
       * a subsystem's capabilities.
       */
      std::string Operation() {
    	std::string result = "Facade initializes subsystems:\n";
    	result += this->subsystem1_->Operation1();
    	result += this->subsystem2_->Operation1();
    	result += "Facade orders subsystems to perform the action:\n";
    	result += this->subsystem1_->OperationN();
    	result += this->subsystem2_->OperationZ();
    	return result;
      }
    };
    
    /**
     * The client code works with complex subsystems through a simple interface
     * provided by the Facade. When a facade manages the lifecycle of the subsystem,
     * the client might not even know about the existence of the subsystem. This
     * approach lets you keep the complexity under control.
     */
    void ClientCode(Facade *facade) {
      // ...
      std::cout << facade->Operation();
      // ...
    }
    /**
     * The client code may have some of the subsystem's objects already created. In
     * this case, it might be worthwhile to initialize the Facade with these objects
     * instead of letting the Facade create new instances.
     */
    
    int main() {
      Subsystem1 *subsystem1 = new Subsystem1;
      Subsystem2 *subsystem2 = new Subsystem2;
      Facade *facade = new Facade(subsystem1, subsystem2);
      ClientCode(facade);
    
      delete facade;
    
      return 0;
    }
    
    c
    #include <stdio.h>
    
    // 定义子系统A
    typedef struct subsystemA {
    	void (*operationA)(struct subsystemA* subsystem);
    } SubsystemA;
    
    // 定义子系统B
    typedef struct subsystemB {
    	void (*operationB)(struct subsystemB* subsystem);
    } SubsystemB;
    
    // 定义子系统C
    typedef struct subsystemC {
    	void (*operationC)(struct subsystemC* subsystem);
    } SubsystemC;
    
    // 定义外观
    typedef struct facade {
    	SubsystemA subsystemA;
    	SubsystemB subsystemB;
    	SubsystemC subsystemC;
    	void (*operation)(struct facade* facade);
    } Facade;
    
    // 实现子系统A的操作
    void operationA(SubsystemA* subsystem) {
    	printf("SubsystemA operation.\n");
    }
    
    // 实现子系统B的操作
    void operationB(SubsystemB* subsystem) {
    	printf("SubsystemB operation.\n");
    }
    
    // 实现子系统C的操作
    void operationC(SubsystemC* subsystem) {
    	printf("SubsystemC operation.\n");
    }
    
    // 实现外观的操作
    void operation(Facade* facade) {
    	facade->subsystemA.operationA(&facade->subsystemA);
    	facade->subsystemB.operationB(&facade->subsystemB);
    	facade->subsystemC.operationC(&facade->subsystemC);
    }
    
    int main() {
    	Facade facade;
    
    	facade.subsystemA.operationA = operationA;
    	facade.subsystemB.operationB = operationB;
    	facade.subsystemC.operationC = operationC;
    	facade.operation = operation;
    
    	facade.operation(&facade);
    
    	return 0;
    }
    

    享元模式 - 通过抽取共享元素,减少空间占用

    • 前提 - 工厂模式: 享元模式可以使用工厂模式对享元的创建和使用进行优化

    • 概念: 运用共享技术有效地支持大量细粒度的对象。

    • 规则: 其本质是一种优化,针对于大量对象中共享且不变的单元,对其进行共享,从而实现代码的优化

    • 实现细节: 使用工厂模式,创建享元基类,之后情景类(外在状态)调用享元工厂模式,根据情景创建/调用享元,并为客户端提供服务。
      改写方法:将修改成员分类(固定状态—可变状态)-> 将固定状态设定为常量,并使用调用参数对固定状态进行引用 -> 创建享元缓存池

    • 应用场景: 程序需要支持大量对象,且内存有限。像COW技巧,但是没有W这一步;

    • 示意图:
      image

    • 代码实现:

    c++
    /**
     * Flyweight Design Pattern
     *
     * Intent: Lets you fit more objects into the available amount of RAM by sharing
     * common parts of state between multiple objects, instead of keeping all of the
     * data in each object.
     */
    
    struct SharedState
    {
    	std::string brand_;
    	std::string model_;
    	std::string color_;
    
    	SharedState(const std::string &brand, const std::string &model, const std::string &color)
    		: brand_(brand), model_(model), color_(color)
    	{
    	}
    
    	friend std::ostream &operator<<(std::ostream &os, const SharedState &ss)
    	{
    		return os << "[ " << ss.brand_ << " , " << ss.model_ << " , " << ss.color_ << " ]";
    	}
    };
    
    struct UniqueState
    {
    	std::string owner_;
    	std::string plates_;
    
    	UniqueState(const std::string &owner, const std::string &plates)
    		: owner_(owner), plates_(plates)
    	{
    	}
    
    	friend std::ostream &operator<<(std::ostream &os, const UniqueState &us)
    	{
    		return os << "[ " << us.owner_ << " , " << us.plates_ << " ]";
    	}
    };
    
    /**
     * The Flyweight stores a common portion of the state (also called intrinsic
     * state) that belongs to multiple real business entities. The Flyweight accepts
     * the rest of the state (extrinsic state, unique for each entity) via its
     * method parameters.
     */
    class Flyweight
    {
    private:
    	SharedState *shared_state_;
    
    public:
    	Flyweight(const SharedState *shared_state) : shared_state_(new SharedState(*shared_state))
    	{
    	}
    	Flyweight(const Flyweight &other) : shared_state_(new SharedState(*other.shared_state_))
    	{
    	}
    	~Flyweight()
    	{
    		delete shared_state_;
    	}
    	SharedState *shared_state() const
    	{
    		return shared_state_;
    	}
    	void Operation(const UniqueState &unique_state) const
    	{
    		std::cout << "Flyweight: Displaying shared (" << *shared_state_ << ") and unique (" << unique_state << ") state.\n";
    	}
    };
    /**
     * The Flyweight Factory creates and manages the Flyweight objects. It ensures
     * that flyweights are shared correctly. When the client requests a flyweight,
     * the factory either returns an existing instance or creates a new one, if it
     * doesn't exist yet.
     */
    class FlyweightFactory
    {
    	/**
    	 * @var Flyweight[]
    	 */
    private:
    	std::unordered_map<std::string, Flyweight> flyweights_;
    	/**
    	 * Returns a Flyweight's string hash for a given state.
    	 */
    	std::string GetKey(const SharedState &ss) const
    	{
    		return ss.brand_ + "_" + ss.model_ + "_" + ss.color_;
    	}
    
    public:
    	FlyweightFactory(std::initializer_list<SharedState> share_states)
    	{
    		for (const SharedState &ss : share_states)
    		{
    			this->flyweights_.insert(std::make_pair<std::string, Flyweight>(this->GetKey(ss), Flyweight(&ss)));
    		}
    	}
    
    	/**
    	 * Returns an existing Flyweight with a given state or creates a new one.
    	 */
    	Flyweight GetFlyweight(const SharedState &shared_state)
    	{
    		std::string key = this->GetKey(shared_state);
    		if (this->flyweights_.find(key) == this->flyweights_.end())
    		{
    			std::cout << "FlyweightFactory: Can't find a flyweight, creating new one.\n";
    			this->flyweights_.insert(std::make_pair(key, Flyweight(&shared_state)));
    		}
    		else
    		{
    			std::cout << "FlyweightFactory: Reusing existing flyweight.\n";
    		}
    		return this->flyweights_.at(key);
    	}
    	void ListFlyweights() const
    	{
    		size_t count = this->flyweights_.size();
    		std::cout << "\nFlyweightFactory: I have " << count << " flyweights:\n";
    		for (std::pair<std::string, Flyweight> pair : this->flyweights_)
    		{
    			std::cout << pair.first << "\n";
    		}
    	}
    };
    
    // ...
    void AddCarToPoliceDatabase(
    	FlyweightFactory &ff, const std::string &plates, const std::string &owner,
    	const std::string &brand, const std::string &model, const std::string &color)
    {
    	std::cout << "\nClient: Adding a car to database.\n";
    	const Flyweight &flyweight = ff.GetFlyweight({brand, model, color});
    	// The client code either stores or calculates extrinsic state and passes it
    	// to the flyweight's methods.
    	flyweight.Operation({owner, plates});
    }
    
    /**
     * The client code usually creates a bunch of pre-populated flyweights in the
     * initialization stage of the application.
     */
    
    int main()
    {
    	FlyweightFactory *factory = new FlyweightFactory({{"Chevrolet", "Camaro2018", "pink"}, {"Mercedes Benz", "C300", "black"}, {"Mercedes Benz", "C500", "red"}, {"BMW", "M5", "red"}, {"BMW", "X6", "white"}});
    	factory->ListFlyweights();
    
    	AddCarToPoliceDatabase(*factory,
    							"CL234IR",
    							"James Doe",
    							"BMW",
    							"M5",
    							"red");
    
    	AddCarToPoliceDatabase(*factory,
    							"CL234IR",
    							"James Doe",
    							"BMW",
    							"X1",
    							"red");
    	factory->ListFlyweights();
    	delete factory;
    
    	return 0;
    }
    
    c
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    // 享元接口
    typedef struct {
    	void (*operation)(void* data);
    } Flyweight;
    
    // 具体享元实现
    typedef struct {
    	Flyweight base;
    	char name[50];
    } ConcreteFlyweight;
    
    void ConcreteFlyweight_operation(void* data) {
    	ConcreteFlyweight* flyweight = (ConcreteFlyweight*)data;
    	printf("ConcreteFlyweight Operation: %s\n", flyweight->name);
    }
    
    // 享元工厂
    typedef struct {
    	int capacity;
    	int count;
    	Flyweight** flyweights;
    } FlyweightFactory;
    
    FlyweightFactory* FlyweightFactory_create(int capacity) {
    	FlyweightFactory* factory = (FlyweightFactory*)malloc(sizeof(FlyweightFactory));
    	factory->capacity = capacity;
    	factory->count = 0;
    	factory->flyweights = (Flyweight**)malloc(capacity * sizeof(Flyweight*));
    	return factory;
    }
    
    Flyweight* FlyweightFactory_getFlyweight(FlyweightFactory* factory, const char* name) {
    	for (int i = 0; i < factory->count; i++) {
    		ConcreteFlyweight* flyweight = (ConcreteFlyweight*)factory->flyweights[i];
    		if (strcmp(flyweight->name, name) == 0) {
    			return &flyweight->base;
    		}
    	}
    
    	if (factory->count >= factory->capacity) {
    		printf("FlyweightFactory is full\n");
    		return NULL;
    	}
    
    	ConcreteFlyweight* flyweight = (ConcreteFlyweight*)malloc(sizeof(ConcreteFlyweight));
    	flyweight->base.operation = ConcreteFlyweight_operation;
    	strcpy(flyweight->name, name);
    	factory->flyweights[factory->count] = (Flyweight*)flyweight;
    	factory->count++;
    	return &flyweight->base;
    }
    
    void FlyweightFactory_destroy(FlyweightFactory* factory) {
    	for (int i = 0; i < factory->count; i++) {
    		free(factory->flyweights[i]);
    	}
    	free(factory->flyweights);
    	free(factory);
    }
    
    // 客户端模块
    int main() {
    	FlyweightFactory* factory = FlyweightFactory_create(5);
    
    	// 获取享元对象并执行操作
    	Flyweight* flyweight1 = FlyweightFactory_getFlyweight(factory, "Object1");
    	if (flyweight1 != NULL) {
    		flyweight1->operation(flyweight1);
    	}
    
    	Flyweight* flyweight2 = FlyweightFactory_getFlyweight(factory, "Object2");
    	if (flyweight2 != NULL) {
    		flyweight2->operation(flyweight2);
    	}
    
    	Flyweight* flyweight3 = FlyweightFactory_getFlyweight(factory, "Object1"); // 已存在的对象,直接返回
    	if (flyweight3 != NULL) {
    		flyweight3->operation(flyweight3);
    	}
    
    	FlyweightFactory_destroy(factory);
    
    	return 0;
    }
    

代理模式 -不基于对象的方法的封装

  • 概念: 为其他对象提供一种代理以控制对这个对象的访问。

  • 规则: 其本质是在客户端和服务端之间插入一层代理,实现对服务端提供服务的优化,如实现延迟写等

  • 实现细节: 接口的创建可以通过继承服务类/抽取接口创建接口->创建代理类,其中需要包含一个存储指向服务类的引用的成员变量。同时,代理方法的实现是面向特定需求的,完成任务后应该将后续任务委派给服务类。在操作系统中,文件系统中的日志系统就是对底层硬盘读写的代理。

  • 应用场景: 延迟初始化(虚拟代理),即COW;访问控制(保护代理),即权限控制;本地执行远程服务(远程代理),类似于SSH;记录日志请求(日志记录代理),文件系统和数据库的日志系统;缓存请求结果(缓存代理),即快表;智能引用,文件系统/缓存池。

  • 示意图:
    image

  • 注: 装饰模式是基于客户端的,其生命周期和客户端一致,而代理模式是基于独立的,其自行管理声明周期。

  • 代码实现:

    c++
    #include <iostream>
    /**
     * The Subject interface declares common operations for both RealSubject and the
     * Proxy. As long as the client works with RealSubject using this interface,
     * you'll be able to pass it a proxy instead of a real subject.
     */
    class Subject {
     public:
      virtual void Request() const = 0;
    };
    /**
     * The RealSubject contains some core business logic. Usually, RealSubjects are
     * capable of doing some useful work which may also be very slow or sensitive -
     * e.g. correcting input data. A Proxy can solve these issues without any
     * changes to the RealSubject's code.
     */
    class RealSubject : public Subject {
     public:
      void Request() const override {
    	std::cout << "RealSubject: Handling request.\n";
      }
    };
    /**
     * The Proxy has an interface identical to the RealSubject.
     */
    class Proxy : public Subject {
      /**
       * @var RealSubject
       */
     private:
      RealSubject *real_subject_;
    
      bool CheckAccess() const {
    	// Some real checks should go here.
    	std::cout << "Proxy: Checking access prior to firing a real request.\n";
    	return true;
      }
      void LogAccess() const {
    	std::cout << "Proxy: Logging the time of request.\n";
      }
    
      /**
       * The Proxy maintains a reference to an object of the RealSubject class. It
       * can be either lazy-loaded or passed to the Proxy by the client.
       */
     public:
      Proxy(RealSubject *real_subject) : real_subject_(new RealSubject(*real_subject)) {
      }
    
      ~Proxy() {
    	delete real_subject_;
      }
      /**
       * The most common applications of the Proxy pattern are lazy loading,
       * caching, controlling the access, logging, etc. A Proxy can perform one of
       * these things and then, depending on the result, pass the execution to the
       * same method in a linked RealSubject object.
       */
      void Request() const override {
    	if (this->CheckAccess()) {
    	  this->real_subject_->Request();
    	  this->LogAccess();
    	}
      }
    };
    /**
     * The client code is supposed to work with all objects (both subjects and
     * proxies) via the Subject interface in order to support both real subjects and
     * proxies. In real life, however, clients mostly work with their real subjects
     * directly. In this case, to implement the pattern more easily, you can extend
     * your proxy from the real subject's class.
     */
    void ClientCode(const Subject &subject) {
      // ...
      subject.Request();
      // ...
    }
    
    int main() {
      std::cout << "Client: Executing the client code with a real subject:\n";
      RealSubject *real_subject = new RealSubject;
      ClientCode(*real_subject);
      std::cout << "\n";
      std::cout << "Client: Executing the same client code with a proxy:\n";
      Proxy *proxy = new Proxy(real_subject);
      ClientCode(*proxy);
    
      delete real_subject;
      delete proxy;
      return 0;
    }
    
    c
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    //定义一个接口
    typedef struct {
    	void (*doOperation)(void *object);
    } IRealObject;
    
    //创建真实对象结构体
    typedef struct {
    	IRealObject interface;
    } RealObject;
    
    //创建代理对象结构体
    typedef struct {
    	IRealObject interface;
    	RealObject real_object;
    } Proxy;
    
    //实现真实对象的操作方法
    void real_operation(void *object)
    {
    	printf("Performing operation in RealObject\n");
    }
    
    //实现代理对象的操作方法
    void proxy_operation(void *object)
    {
    	Proxy *proxy = (Proxy *)object;
    
    	if (proxy == NULL) {
    		printf("proxy is NULL in proxy_operation\n");
    	return;
    	}
    
    	printf("Performing operation in ProxyObject\n");
    
    	if (proxy->real_object.interface.doOperation == NULL) {
    		proxy->real_object.interface.doOperation = real_operation;
    	}
    
    	proxy->real_object.interface.doOperation(&proxy->real_object);
    }
    
    //创建proxy初始化函数
    IRealObject *create_proxy(void)
    {
    	Proxy *proxy = calloc(1, sizeof(Proxy));
    	if (proxy == NULL) {
    		printf("proxy is creat in create_proxy\n");
    		return 0;
    	}
    
    	if (proxy->interface.doOperation == NULL)
    		proxy->interface.doOperation = proxy_operation;
    
    	return &proxy->interface;
    }
    
    //销毁proxy
    void destory_proxy(void *object)
    {
    	Proxy *proxy = (Proxy *)object;
    
    	if (proxy) {
    		free(proxy);
    	}
    }
    
    //客户端代码
    int main()
    {
    	IRealObject *interface = NULL;
    
    	interface = create_proxy();
    
    	//调用代理对象的操作方法
       interface->doOperation(interface);
    
       destory_proxy(interface);
    
    	return 0;
    }
    

参考文献

廖雪峰的官方网站: https://www.liaoxuefeng.com/wiki/1252599548343744/1264742167474528
c语言和设计模式:https://blog.csdn.net/feixiaoxing/category_951264.html
卡码网设计模式精讲:https://github.com/youngyangyang04/kama-DesignPattern
设计模式:https://www.zhihu.com/column/c_1605852722795917312
设计模式:https://www.zhihu.com/people/infinity-65-77/posts
深入设计模式:https://refactoringguru.cn/design-patterns/builder/cpp/example

posted @ 2024-05-08 16:16  David_Dong  阅读(4)  评论(0编辑  收藏  举报