Skip to content

Commit e7f79a6

Browse files
committed
add composite pattern
1 parent 0dabca3 commit e7f79a6

File tree

9 files changed

+410
-1
lines changed

9 files changed

+410
-1
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525

2626
[桥接模式 Bridge](doc/09-桥接.md)
2727

28-
组合模式 Composite
28+
[组合模式 Composite](doc/10-组合.md)
2929

3030
装饰模式 Decorator
3131

code/09_composite/09_composite.sln

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 16
4+
VisualStudioVersion = 16.0.29215.179
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "09_composite", "09_composite.vcxproj", "{7DAEF34B-221D-41C5-BC99-3CFBD756E11C}"
7+
EndProject
8+
Global
9+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
10+
Debug|x64 = Debug|x64
11+
Debug|x86 = Debug|x86
12+
Release|x64 = Release|x64
13+
Release|x86 = Release|x86
14+
EndGlobalSection
15+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
16+
{7DAEF34B-221D-41C5-BC99-3CFBD756E11C}.Debug|x64.ActiveCfg = Debug|x64
17+
{7DAEF34B-221D-41C5-BC99-3CFBD756E11C}.Debug|x64.Build.0 = Debug|x64
18+
{7DAEF34B-221D-41C5-BC99-3CFBD756E11C}.Debug|x86.ActiveCfg = Debug|Win32
19+
{7DAEF34B-221D-41C5-BC99-3CFBD756E11C}.Debug|x86.Build.0 = Debug|Win32
20+
{7DAEF34B-221D-41C5-BC99-3CFBD756E11C}.Release|x64.ActiveCfg = Release|x64
21+
{7DAEF34B-221D-41C5-BC99-3CFBD756E11C}.Release|x64.Build.0 = Release|x64
22+
{7DAEF34B-221D-41C5-BC99-3CFBD756E11C}.Release|x86.ActiveCfg = Release|Win32
23+
{7DAEF34B-221D-41C5-BC99-3CFBD756E11C}.Release|x86.Build.0 = Release|Win32
24+
EndGlobalSection
25+
GlobalSection(SolutionProperties) = preSolution
26+
HideSolutionNode = FALSE
27+
EndGlobalSection
28+
GlobalSection(ExtensibilityGlobals) = postSolution
29+
SolutionGuid = {B4EB24EC-4756-4E63-901B-056C7782CBF6}
30+
EndGlobalSection
31+
EndGlobal

code/09_composite/awt.cpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#include "awt.h"
2+
3+
void Container::add(Component* comp)
4+
{
5+
m_components.push_back(comp);
6+
}
7+
8+
void Container::remove(Component* comp)
9+
{
10+
m_components.remove(comp);
11+
}
12+
13+
void Container::removeAll()
14+
{
15+
m_components.clear();
16+
}
17+
18+
void Container::repaint()
19+
{
20+
cout << "repaint container begin" << endl;
21+
22+
list<Component*>::const_iterator iter = m_components.cbegin();
23+
while (iter != m_components.cend()) {
24+
(*iter)->repaint();
25+
iter++;
26+
}
27+
28+
cout << "repaint container end\n" << endl;
29+
}
30+
31+
Button::Button()
32+
{
33+
}
34+
35+
Button::Button(string label):m_label(label)
36+
{
37+
}
38+
39+
void Button::repaint()
40+
{
41+
if (m_visible) {
42+
cout << "repaint button:" << getLabel() << endl;
43+
}
44+
}
45+
46+
Checkbox::Checkbox()
47+
{
48+
}
49+
50+
Checkbox::Checkbox(string label, bool state):m_label(label),m_state(state)
51+
{
52+
}
53+
54+
void Checkbox::repaint()
55+
{
56+
if (m_visible) {
57+
cout << "repaint checkbox:" << getLabel() << ",state:" << getState() << endl;
58+
}
59+
}

code/09_composite/awt.h

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#pragma once
2+
#include <iostream>
3+
#include <string>
4+
#include <list>
5+
using namespace std;
6+
7+
class Component {
8+
public:
9+
inline bool isVisible() {
10+
return m_visible;
11+
}
12+
inline void setVisible(bool b) {
13+
this->m_visible = b;
14+
}
15+
virtual void repaint() = 0;
16+
protected:
17+
bool m_visible = true;
18+
};
19+
20+
class Container :public Component {
21+
public:
22+
void add(Component* comp);
23+
void remove(Component* comp);
24+
void removeAll();
25+
void repaint() override;
26+
private:
27+
list<Component*> m_components;
28+
};
29+
30+
class Button :public Component {
31+
public:
32+
explicit Button();
33+
explicit Button(string label);
34+
inline string getLabel() {
35+
return m_label;
36+
}
37+
inline void setLabel(string label) {
38+
this->m_label = label;
39+
}
40+
void repaint() override;
41+
private:
42+
string m_label;
43+
};
44+
45+
class Checkbox :public Component {
46+
public:
47+
explicit Checkbox();
48+
explicit Checkbox(string label,bool state);
49+
inline string getLabel() {
50+
return m_label;
51+
}
52+
inline void setLabel(string label) {
53+
this->m_label = label;
54+
}
55+
inline bool getState() {
56+
return m_state;
57+
}
58+
inline void setState(bool state) {
59+
this->m_state = state;
60+
}
61+
void repaint() override;
62+
private:
63+
string m_label;
64+
bool m_state = false;
65+
};

code/09_composite/client.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#include "awt.h"
2+
3+
int main() {
4+
5+
Container panel;
6+
Component* comp1 = new Button("action button");
7+
panel.add(comp1);
8+
Component* comp2 = new Checkbox("male",true);
9+
panel.add(comp2);
10+
comp2 = new Checkbox("female", false);
11+
panel.add(comp2);
12+
panel.repaint();
13+
14+
panel.remove(comp2);
15+
panel.repaint();
16+
17+
panel.removeAll();
18+
panel.repaint();
19+
return 0;
20+
}

doc/10-组合.md

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
# 组合
2+
3+
组合多个对象形成树形结构以表示具有部分-整体关系的层次结构。组合模式让客户端可以统一对待单个对象和组合对象。
4+
5+
## UML
6+
7+
* Component(抽象构件): Component是一个抽象类,定义了构件的一些公共接口,具体的实现在叶子构件和容器构件中进行
8+
* Leaf(叶子构件): 它代表树形结构中的叶子节点对象,叶子构件没有子节点,它实现了在抽象构件中定义的行为。
9+
* Composite(容器构件): 容器构件通过聚合关系包含子构件,子构件可以是容器构件,也可以是叶子构件
10+
11+
### 安全组合
12+
13+
![figure9_composite_safe](img/figure9_composite_safe.png)
14+
15+
严格区分叶子节点和容器节点, 抽象节点只具有最少的公共接口, 容器节点包含大量的容器操作接口; 对于叶子节点则不需要添加容器节点的接口,符合接口隔离原则. 不过客户端使用需要区别对待叶子节点和容器节点
16+
17+
18+
### 透明组合
19+
20+
![figure9_composite_glass](img/figure9_composite_glass.png)
21+
22+
顾名思义, 客户端使用时不需要区分对待容器节点和叶子节点,他们有基本一样的接口, 公共接口都定义在抽象节点. 叶子节点时,一些适用于容器节点的接口需要空实现或抛异常等处理
23+
24+
## 优缺点
25+
26+
* 优点
27+
* 清楚地定义分层次的复杂对象,表示出复杂对象的层次结构,让客户端忽略层次的差异
28+
* 客户端可以一致地使用层次结构中各个层次的对象,而不必关心其具体构件的行为如何实现
29+
* 在组合模式中增加新的叶子构件和容器构件非常方便,易于扩展,符合开闭原则
30+
* 为树形结构的案例提供了解决方案
31+
32+
* 缺点
33+
* 子构件或容器构件的行为受限制,因为它们来自相同的抽象层。如果要定义某个容器或者某个叶子节点特有的方法,那么要求在运行时判断对象类型,增加了代码的复杂度。
34+
35+
## 使用场景
36+
37+
* 系统中需要用到树形结构
38+
* 系统中能够分离出容器节点和叶子节点
39+
* 具有整体和部门的层次结构中,能够通过某种方式忽略层次差异,使得客户端可以一致对待
40+
41+
## 用例
42+
43+
Java中的AWT,Swing GUI编程,Qt WidgetGUI编程或者MFC图形化编程基本上都有一个组件树,有具体的控件,有容器控件,都是组合模式的经典使用.
44+
45+
[code](../code/09_composite)
46+
47+
```c++
48+
// awt.h
49+
50+
#pragma once
51+
#include <iostream>
52+
#include <string>
53+
#include <list>
54+
using namespace std;
55+
56+
class Component {
57+
public:
58+
inline bool isVisible() {
59+
return m_visible;
60+
}
61+
inline void setVisible(bool b) {
62+
this->m_visible = b;
63+
}
64+
virtual void repaint() = 0;
65+
protected:
66+
bool m_visible = true;
67+
};
68+
69+
class Container :public Component {
70+
public:
71+
void add(Component* comp);
72+
void remove(Component* comp);
73+
void removeAll();
74+
void repaint() override;
75+
private:
76+
list<Component*> m_components;
77+
};
78+
79+
class Button :public Component {
80+
public:
81+
explicit Button();
82+
explicit Button(string label);
83+
inline string getLabel() {
84+
return m_label;
85+
}
86+
inline void setLabel(string label) {
87+
this->m_label = label;
88+
}
89+
void repaint() override;
90+
private:
91+
string m_label;
92+
};
93+
94+
class Checkbox :public Component {
95+
public:
96+
explicit Checkbox();
97+
explicit Checkbox(string label,bool state);
98+
inline string getLabel() {
99+
return m_label;
100+
}
101+
inline void setLabel(string label) {
102+
this->m_label = label;
103+
}
104+
inline bool getState() {
105+
return m_state;
106+
}
107+
inline void setState(bool state) {
108+
this->m_state = state;
109+
}
110+
void repaint() override;
111+
private:
112+
string m_label;
113+
bool m_state = false;
114+
};
115+
```
116+
117+
```c++
118+
// awt.cpp
119+
120+
#include "awt.h"
121+
122+
void Container::add(Component* comp)
123+
{
124+
m_components.push_back(comp);
125+
}
126+
127+
void Container::remove(Component* comp)
128+
{
129+
m_components.remove(comp);
130+
}
131+
132+
void Container::removeAll()
133+
{
134+
m_components.clear();
135+
}
136+
137+
void Container::repaint()
138+
{
139+
cout << "repaint container begin" << endl;
140+
141+
list<Component*>::const_iterator iter = m_components.cbegin();
142+
while (iter != m_components.cend()) {
143+
(*iter)->repaint();
144+
iter++;
145+
}
146+
147+
cout << "repaint container end\n" << endl;
148+
}
149+
150+
Button::Button()
151+
{
152+
}
153+
154+
Button::Button(string label):m_label(label)
155+
{
156+
}
157+
158+
void Button::repaint()
159+
{
160+
if (m_visible) {
161+
cout << "repaint button:" << getLabel() << endl;
162+
}
163+
}
164+
165+
Checkbox::Checkbox()
166+
{
167+
}
168+
169+
Checkbox::Checkbox(string label, bool state):m_label(label),m_state(state)
170+
{
171+
}
172+
173+
void Checkbox::repaint()
174+
{
175+
if (m_visible) {
176+
cout << "repaint checkbox:" << getLabel() << ",state:" << getState() << endl;
177+
}
178+
}
179+
```
180+
181+
```c++
182+
// client.cpp
183+
184+
#include "awt.h"
185+
186+
int main() {
187+
Container panel;
188+
Component* comp1 = new Button("action button");
189+
panel.add(comp1);
190+
Component* comp2 = new Checkbox("male",true);
191+
panel.add(comp2);
192+
comp2 = new Checkbox("female", false);
193+
panel.add(comp2);
194+
panel.repaint();
195+
196+
panel.remove(comp2);
197+
panel.repaint();
198+
199+
panel.removeAll();
200+
panel.repaint();
201+
return 0;
202+
}
203+
```
9.7 KB
Loading

doc/img/figure9_composite_safe.png

9.02 KB
Loading

0 commit comments

Comments
 (0)