23种设计模式-结构型模式
笔记模板
模式
- 前提 - 模式:
- 概念:
- 规则:
- 实现细节:
- 应用场景:
- 示意图:
- 代码实现:
创建型模式
- 适配器、桥接、组合、装饰、外观、享元、代理。
适配器模式 - 接口兼容思想
-
概念: 将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作(核心:适配器)
-
规则: 通过一个类,实现从调用者(客户端)到被调用者(服务端)的接口实现
-
实现细节: 其分为对象适配器和类适配器,对象适配器其功能为接口的转换(一对一,即单一继承),类适配器为多重继承,即继承了不同类的产物,可以更好的封装适配器(多对多,即多重继承)
客户端接口 ---适配器--- 服务端实现;
实现时需要注意,使用构造函数/调用方法传递的方式实现服务对象的引用;
实现方法以客户端接口为准,即使用服务端实现完成对客户端接口的适配 -
应用场景: 1.使用类,但是其接口与其他代码不兼容;2.复用属于同一个继承体系,但是存在额外共性的类。这些额外共性可以使用适配器实现(类似于装饰器);操作系统本质就是一种适配器,按其标准实现了对硬件的封装,从而使上层的软件能够以标准接口,如POSIX等,实现对其的调用。
-
示意图:
对象适配器:
类适配器
-
代码实现:
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.需要在运行时切换不同的实现方法
-
示意图:
-
代码实现:
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等,其在绘制时,使用了树形结构进行逐层调用与绘制
-
应用场景: 实现树状对象结构;客户端能够以相同方式处理简单和复杂元素
-
示意图:
-
代码实现:
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; }
装饰器模式 - 使对象和方法解耦,是桥接模式的另一种实现
-
概念: 动态地给一个对象添加一些额外的职责。就增加功能来说,相比生成子类更为灵活;
-
规则: 核心需求是防止需求的增加导致子类数量的爆炸;其核心方法是利用聚合/组合思想,实现封装器,而不是使用继承。封装器需要实现与封装对象相同的接口,从而使客户端可以对采用同一接口进行调用
-
实现细节: 在客户端,客户需要将基础对象放入一系列装饰中,形成栈结构;在装饰器中,需要实现装饰基类以实现基础接口,同时,实现具体装饰类实现装饰所需的操作
-
应用场景: 无需修改原始代码的情况下使用对象,并为对象添加额外的方法(行为);面向对象方法的扩展受到无法(难以)继承的限制;
-
示意图:
-
代码实现:
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)可以理解为外观模式的应用。
-
示意图:
-
代码实现:
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这一步;
-
示意图:
-
代码实现:
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;记录日志请求(日志记录代理),文件系统和数据库的日志系统;缓存请求结果(缓存代理),即快表;智能引用,文件系统/缓存池。
-
示意图:
-
注: 装饰模式是基于客户端的,其生命周期和客户端一致,而代理模式是基于独立的,其自行管理声明周期。
-
代码实现:
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