Composite 模式作为 C++ 组件
Composite 模式作为可重用的 C++ 模板类
引言
本文介绍了一个可重用的 C++ 模板类,可以轻松地用于替代组合设计模式的实现。它具有以下优点
- 它消除了重复的任务——模式的骨架实现。
- 即使对组合模式的结构略知一二的初学者也可以非常轻松地使用它。
- 代码重用反过来可以减少错误。
- 该模板类也可以应用于现有类,而不会出现太大问题,从而使它们成为组合类。
背景
组合设计模式是 Gang of Four (GoF) 确定的 23 种流行设计模式之一。可以在 此处 找到组合模式的传统实现。

使用这种传统风格,每次您都必须为 Composite
类创建容器基础设施。 此外,请注意,Component
类不需要 Container
函数,如 Add()
、Remove()
、GetChild()
等。 它们仅在 Composite
类中是必需的。
本文介绍的模板类可帮助您专注于将在 Component
、Composite
和 Leaf
类中实现的业务逻辑,而不是每次都在 Composite
类中起草设计基础设施,例如 Add()
、Remove()
、GetChild()
等。
这种新技术的局限性
- 您必须在您的应用程序中使用 Composite.h 头文件。
- 此头文件使用 STL 头文件,例如
<vector>
和<algorithm>
; 如果您不喜欢使用 STL,则必须根据您的目的修改模板类。 - 您必须在您的
Composite
类中创建一个继承契约,将其与您的Component
类联系起来。
使用代码
以下代码包含两个部分
第 1 部分 是 Composite<>
类的实现。 这是一个非常简单的类,您可以根据需要轻松地自行修改。
第 2 部分 是一个示例程序,用于演示 Composite<>
类在简单的电子元件仿真程序中的用法。
第 1 部分 - 组合类
#ifndef COMPOSITE_H_
#define COMPOSITE_H_
#include <vector>
#include <algorithm>
/*
* This library provide a reusable C++ template class which can be easily re used -
* in place of implementing Composite design pattern.
* Composite design pattern is one among the 23 popular design patterns -
* identified by Gang of Four (GoF).
* In a Composite pattern there will be three type of classes like, component,
* composite and leaf.
* Composite and leaf are derived from Component. Composite is a container class -
* which can store many other Components.
*/
namespace GoFPatterns
{
using namespace std;
/*
* This template class automatically inherits itself from the given Component type
* and in addition it provides the containment features to the expanded template type.
*/
template<typename Component>
class Composite: public Component
{
protected:
vector<Component*> children; //Child components list.
public:
/*
* An iterator type is defined which can be used from Composite class
* To perform extensive operations on the Children list like Insert, Search etc.
* This is provided just for Ease of use for Composite class developers.
*/
typedef typename vector<Component*>::iterator ChildIterator;
/*
* Add a Component to the child list.
* Check to avoid duplication of same child in the list.
*/
void AddChild(Component* child)
{
ChildIterator itr = find(children.begin(),children.end(),child);
if( itr == children.end())
{
children.push_back(child);
}
}
/*
* Remove a component from the child list if it exist there.
*/
void RemoveChild(Component* child)
{
ChildIterator itr = find(children.begin(),children.end(),child);
if( itr != children.end())
{
children.erase(itr);
}
}
/*
* Remove all child from the list.
*/
void Clear()
{
children.clear();
}
virtual ~Composite()
{
}
}; //End class Composite
}//End name space GoFPatterns
#endif /* COMPOSITE_H_ */
示例程序
#include <iostream>
#include "Composite.h"
/*
* This is program is an example use of Composite<> template class.
* The program shows an Electronic system.
* The system contains the following type of components.
* * Resistor
* * Capacitor
* * ICChip
* * PCB
* All these components share the common features of
* "ElectronicComponet"-abstract class. * In terms of Composite pattern,
* the class "ElectronicComponent" acts as the "Component"
* The Resistor & Capacitor classes acts like Leafs since they don't have
* further sub division.
* ICChip s contains many Resistors and Capacitors inside it, so it will be -
* a Composite of Electronic Components Composite<ElectronicComponent>.
* Further more, the PCB ( Printed Circuit board ) can contains, Resistor, -
* Capacitor and ICChips on it. So that also is a Composite Electronic Component.
*
* Simply, all Electronic Components has some common feature that it accept a Voltage
* and Current as Input and generates a varied value of Voltage and current as Output.
* So a function named DoFunction() is there which does the components actual processing.
*
* Also all Electronic components will have a specification.
* For e.g. Resister has X number of Ohms, and Capacitor has X micro fared etc.
* So a function named PrintSpec() is there which prints the component spec .
*/
namespace GoFExample
{
using namespace std;
using namespace GoFPatterns;
/*
* The COMPONENT class which declares the common functionalities -
* of all Electronic Components.
*/
class ElectronicComponent
{
public:
virtual void PrintSpec(ostream& ostr, string prefix = "")= 0;
virtual void DoFunction(float& voltage, float& current) = 0;
};
/*
* Resistor is a LEAF class which is directly inherited from the -
* ElectronicComponet class.
*/
class Resistor:public ElectronicComponent
{
float resistance_Ohm; // Resistance value of resistor.
Resistor(){}
public:
/*
* Constructor - initialize the Resistance value.
*/
Resistor(float ohm)
:resistance_Ohm(ohm)
{}
/*
* Prints the Resistor's specification.
*/
void PrintSpec(ostream& ostr, string prefix = "")
{
ostr<<prefix<<"Resistor ("<< resistance_Ohm <<" Ohm )"<<endl;
}
/*
* Performs the Resistor's real function of modifying input Voltage & Current.
* Electrical engineers, please help :)
* Now I just put a printing of Voltage and current as place holder.
*/
void DoFunction(float& voltage, float& current)
{
cout<<endl<<"Resistor Input ("<<voltage<<" V ,"<<current<<" Amp)
Resistance = "<< resistance_Ohm <<endl;
}
};
/*
* Capacitor is a LEAF class which is directly inherited from the -
* ElectronicComponet class.
*/
class Capacitor:public ElectronicComponent
{
float capacitance_muF; //Capacitance value in micro fared.
Capacitor(){}
public:
/*
* Constructor - initialize the capacitance value.
*/
Capacitor(float muF)
:capacitance_muF(muF)
{
}
/*
* Prints the Capacitor's specification.
*/
void PrintSpec(ostream& ostr, string prefix = "")
{
ostr<<prefix<<"Capacitor ("<< capacitance_muF <<" muF )"<<endl;
}
/*
* Performs the Capacitor's real function of modifying input Voltage & Current.
* Electrical engineers, please help :)
* Now I just put a printing of Voltage and current as place holder.
*/
void DoFunction(float& voltage, float& current)
{
cout<<endl<<"Capacitor Input ("<<voltage<<" V ,"<<current<<" Amp)
Capacitance ="<< capacitance_muF<<endl;
}
};
/*
* ICChip is a COMPOSITE class which consist of many ElectronicComponents -
* such as Resistors & Capacitors.
* So it can be said a Composite of ElectronicComponents. Thus it is inherited from -
* Composite<ElectronicComponent>. This makes it a container class of -
* other ElectronicComponents and at the same time it, it by itself -
* an ElectronicComponent.
*/
class ICChip:public Composite<ElectronicComponent>
{
public:
/*
* PrintSpec of ICChip prints no only the spec of the Chip itself
* but also the Spec of its Child components in a TAB ("\t") intended format.
*/
void PrintSpec(ostream& ostr, string prefix = "")
{
ostr<<prefix<<"ICChip With "<< children.size()<<
" Components " <<endl;
for( unsigned int i = 0; i < children.size(); i++)
{
ostr<<prefix;
children[i]->PrintSpec(ostr,"\t");
}
}
/*
* Real functioning of ICChip is achieved by passing its input Voltage & Current
* To the sub components inside it.
* So the DoFunction - of ICChip passes its input Voltage & Current to all the
* child component's DoFunction .
*/
void DoFunction(float& voltage, float& current)
{
cout<<endl<<"ICChip Input ("<<voltage<<" V ,"<<current<<" Amp)";
for( unsigned int i = 0; i < children.size(); i++)
{
children[i]->DoFunction(voltage,current);
}
}
};
/*
* ICChip is a COMPOSITE class which consist of many ElectronicComponents -
* such as Resistors, Capacitors or ICChips.
* So it can be said a Composite of ElectronicComponents. Thus it is inherited from -
* Composite<ElectronicComponent>. This makes it a container class of -
* other ElectronicComponents and at the same time it, it by itself -
* an ElectronicComponent.
*/
class PCB:public Composite<ElectronicComponent>
{
public:
/*
* PrintSpec of PCB prints no only the spec of the PCB itself
* but also the Spec of its Child components in a TAB ("\t") intended format.
*/
void PrintSpec(ostream& ostr, string prefix = "")
{
ostr<<prefix<<"PCB With "<< children.size()<< " Components " <<endl;
for( unsigned int i = 0; i < children.size(); i++)
{
ostr<<prefix;
children[i]->PrintSpec(ostr,"\t");
}
}
/*
* Real functioning of PCB is achieved by sending its input Voltage & Current
* To the sub components inside it.
* So the DoFunction - of PCB send its input Voltage & Current to all the
* child components inside it.
*/
void DoFunction(float& voltage, float& current)
{
cout<<endl<<"PCB Input ("<<voltage<<" V ,"<<current<<" Amp) ";
for( unsigned int i = 0; i < children.size(); i++)
{
children[i]->DoFunction(voltage,current);
}
}
};
}//end name space GoFExample
using namespace GoFExample;
/*
* Program entry point; main() function
*/
int main()
{
Resistor r1(50), r2(70); //Define Resistors
Capacitor c1(200),c2(300); //Define Capacitors
ICChip ic1; //Create a Chip
ic1.AddChild(new Resistor(2000)); // Add a Resistor inside the ICChip
ic1.AddChild(new Capacitor(1000)); // Add a Capacitor inside the ICChip
PCB pcb1; //Make PCB Object and add the Resistor, Capacitors and ICChip on it
pcb1.AddChild(&r1);
pcb1.AddChild(&c1);
pcb1.AddChild(&c2);
pcb1.AddChild(&ic1);
pcb1.AddChild(&ic1); // Duplicate child entries are ignored.
cout<<"\n=========== Printing the PCB Spec =========="<<endl;
pcb1.PrintSpec(cout);
float v =110, i = 5;
cout<<"\n=========== DoFunction(110,5) of PCB =========="<<endl;
pcb1.DoFunction(v,i);
cout<<"\n=========== Removing c2 from PCB =========="<<endl;
pcb1.RemoveChild(&c2);
cout<<"\n=========== Printing the PCB Spec =========="<<endl;
pcb1.PrintSpec(cout);
return 0;
}
程序输出
=========== Printing the PCB Spec ==========
PCB With 4 Components
Resistor (50 Ohm )
Capacitor (200 muF )
Capacitor (300 muF )
ICChip With 2 Components
Resistor (2000 Ohm )
Capacitor (1000 muF )
=========== DoFunction(110,5) of PCB ==========
PCB Input (110 V ,5 Amp)
Resistor Input (110 V ,5 Amp) Resistance = 50
Capacitor Input (110 V ,5 Amp) Capacitance =200
Capacitor Input (110 V ,5 Amp) Capacitance =300
ICChip Input (110 V ,5 Amp)
Resistor Input (110 V ,5 Amp) Resistance = 2000
Capacitor Input (110 V ,5 Amp) Capacitance =1000
=========== Removing c2 from PCB ==========
=========== Printing the PCB Spec ==========
PCB With 3 Components
Resistor (50 Ohm )
Capacitor (200 muF )
ICChip With 2 Components
Resistor (2000 Ohm )
Capacitor (1000 muF )
兴趣点
当我考虑将 Composite<>
模式组件化时,我希望我将获得一个复杂的模板类才能达到目的。 但正如您所看到的,Composite<>
类非常简单,以至于您可能认为它不是必需的。 但实际上,有时最简单的解决方案可以实现您想要的效果。
在这种情况下,在库端,Composite<>
继承到其类型名称 (Component
) 就发挥了作用。
template<typename Component>
class Composite: public Component
{
在客户端,Composite
类从 Composite<Component>
的继承很快将其变成了具有 AddChild()
、RemoveChild()
等函数的 Container
。
class ICChip:public Composite<ElectronicComponent>
{
我添加了 AddChild()
、RemoveChild()
和 Clear()
方法,只是为了不暴露 children 的 <vector>
。
历史
- 2009 年 4 月 17 日:初始版本