Composite组合 —— 对象结构型模式
- 意图
将对象组合成树形结构以表示“部分——整体”的层次结构。Composite使得用户对单个对象和组合对象的使用具有一致性。
- 使用性
- 你想表示对象的部分 - 整体层次结构
- 你希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有独享
- 结构
典型结构如下:
- 参与者
- Component(Graphic)
- 为组合中的对象声明接口
- 在适当情况下,实现所有类共有接口的缺省行为
- 声明一个接口用于访问和管理Component的子组件
- (可选)在递归结构中定义一个接口,用于访问一个父组件,并在合适情况下实现它
- Leaf(Rectangle,Line,Text等)
- 在组合中表示叶节点对象,叶节点没有子节点
- 在组合中定义图元对象的行为
- Composite(Picture)
- 定义有子部件的那些部件的行为
- 存储子部件
- 在Component接口中实现与子部件有关的操作
- Cilent
- 相关模式
通常,部件 - 父部件连接用于 Responsibility of Chain模式
- Decorator模式经常与Composite模式一起使用。当装饰和组合一起使用时,它们通常有一个公共的父类。因此装饰必须支持具有Add、Remove、GetChild操作的Component接口
- Flyweight 让你共享组件,但不再能引用其父组件
- Iterator 可用来遍历Composite
- Visitor 将本来应该分布在Composite和Leaf类中的操作和行为局部化
- 示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
| #include <iostream> #include <string> #include <vector>
#ifndef PATTERNDESIGN_DECORATOR_H #define PATTERNDESIGN_DECORATOR_H
void test_composite() ;
class Equipment { public: Equipment(std::string name, int price) : name(name),price(price) {} virtual ~Equipment() = default; virtual std::string get_name() { return name; } virtual int get_price() { return price; }
virtual void add(Equipment* equipment) {} virtual void remove(Equipment* equipment) {}
virtual Equipment* get_child(int index) { return nullptr; }
protected: std::string name; int price; };
class Mouse : public Equipment{ public: Mouse(std::string name, int price) : Equipment(name,price) {
} virtual int get_price() { return price * 0.9 ; } };
class CPU : public Equipment { public: CPU(std::string name, int price, std::string type) : Equipment(name, price), type(type) {
} private: std::string type; };
class GraphicCards :public Equipment { public : GraphicCards(std::string name, int price) : Equipment(name, price) {
} virtual int get_price() { return price * 2; } };
class MainBoard : public Equipment { public: MainBoard(std::string name, int price) : Equipment(name, price) {
} virtual void add(Equipment* equipment) { if (equipment == nullptr) return; children.push_back(equipment); } virtual void remove(Equipment* equipment) { if (equipment == nullptr) return ; for (auto iter = children.begin(); iter != children.end(); iter++) { if (*iter == equipment) { children.erase(iter); break; } }
} virtual Equipment* get_child(int index) { if (index < 0 || index >= children.size()) { return nullptr; } return children[index]; }
virtual int get_price() { int sum = price; for (Equipment* p : children) { sum += p->get_price(); } return sum; }
private: std::vector<Equipment*> children; };
#endif
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
#include <iostream> #include "Composite.h" using namespace std;
void test_composite() { cout << "——————————开始测试装饰模式——————————" << endl; Equipment* cpu = new CPU("CPU", 1000, "Intel"); Equipment* graphic_card = new GraphicCards("显卡",4000); Equipment* main_board = new MainBoard("主板",800); main_board->add(cpu); main_board->add(graphic_card); cout << main_board->get_name() << " with " ; cout << main_board->get_child(0)->get_name() << " " << main_board->get_child(1) ->get_name() << endl; cout << "all price:" << main_board->get_price() << endl; main_board->remove(cpu); cout << "主板(带有显卡)当前价格:" << main_board->get_price() << endl; cout << "——————————结束测试装饰模式——————————" << endl; }
|
Decorator(装饰)——对象结构型模式
- 意图
动态地给一个对象添加一些额外的职责。就添加功能来说,Decorator模式相比生成子类更加灵活
- 别名
包装器(wrapper)
- 动机
有时我们希望给某个对象而不是整个类添加一些功能,例如一个图形用户界面工具箱允许你对任意一个用户界面组件添加一些特性(例如边框),或是一些行为(例如窗口滑动)。
使用继承机制是添加功能的一种有效途经,从其他类继承过来的边框特性可以被多个子类的实例所使用,但这种方法不够灵活,因为边框的选择时静态的,用户不能控制对组件加边框的方式和时机。
一种较为灵活的方式就是将组件嵌入另一个对象中,由这个对象添加边框。我们称这个嵌入的对象为装饰。这个装饰与它所装饰的组件接口一致,因此它对使用该组件的客户透明。它将客户请求转发给该组件,并且可能在转发前后执行一些额外的动作(例如画一个边框)。透明性使得你可以递归地嵌套多个装饰,从而可以添加任意多的功能。
- 适用性
以下情况下使用Decorator模式:
- 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责
- 处理那些可以撤销的职责
- 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是,类定义被隐藏,或类定义不能用于生成子类(这个意思就是装饰的意思?)。
- 结构
- 参与者
- Component(VisualComponent)
- ConcreteComponent(TextView)
- Decorator
- 维持一个指向Component对象的指针,并定义一个与Component接口一致的接口
- ConcreteDecorator(BorderDecorator、ScrollDecorator)
- 协作
Decorator将请求转发给它的Component对象,并有可能在转发请求前后执行一些附加的动作
- 相关模式
- Adapter:Decorator模式不同于Adapter模式,因为装饰仅改变对象的职责而不改变它的接口;而适配器将给对象一个全新的接口
- Composite:可以将装饰视为一个退化的、仅有一个组件的组合。然而, 装饰仅给对象添加一些额外的职责——它的目的不在于对象聚集。
- Strategy:用一个装饰可以改变对象的外表;而Strategy模式使你可以改变对象的内核。这是改变对象的两种途经。
- 示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
| #include <iostream>
#ifndef STRUCTURALPATTERNDESIGN_DECORATOR_H #define STRUCTURALPATTERNDESIGN_DECORATOR_H
void test_decorator();
class VisualComponent { public: virtual void draw() = 0; ~VisualComponent() = default; };
class TextLine : public VisualComponent { public : virtual void draw() { std::cout << "画出一个文本框" << std::endl;
} };
class Decorator : public VisualComponent{ public: Decorator(VisualComponent* component) : component(component) {
} virtual ~Decorator() = default; virtual void draw() { component->draw(); }
private: VisualComponent* component;
};
class BorderDecorator : public Decorator { public: BorderDecorator(VisualComponent* component, int width) : Decorator(component), width(width) {
} virtual void draw() { Decorator::draw(); add_border(); }
private: int width; void add_border() { std::cout << "添加边框," << "厚度为" << width << std::endl; }
};
class ScrollDecorator : public Decorator { public: ScrollDecorator(VisualComponent* component) : Decorator(component) {
}
virtual void draw() { Decorator::draw(); add_scroll(); } private: void add_scroll() { std::cout << "添加滚动条" << std::endl; } };
class Window { public: void set_content(VisualComponent* component) { component->draw(); } };
#endif
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| #include <iostream> #include "Decorator.h"
using namespace std; void test_decorator() { cout << "——————————开始测试装饰模式——————————" << endl; Window window;
window.set_content( new ScrollDecorator( new BorderDecorator( new TextLine, 3))); cout << "——————————结束测试装饰模式——————————" << endl; }
|