来源图书:图说设计模式
结构型模式
结构型模式(Structural Pattern)描述如何将类或者对象结合在一起形成更大的结构,就像搭积木,可以通过简单积木的组合形成复杂的、功能更为强大的结构。
结构型模式可以分为类结构型模式和对象结构型模式:
- 类结构型模式关心类的组合,由多个类可以组合成一个更大的系统,在类结构型模式中一般只存在继承关系和实现关系。
- 对象结构型模式关心类与对象的组合,通过关联关系使得在一 个类中定义另一个类的实例对象,然后通过该对象调用其方法。 根据“合成复用原则”,在系统中尽量使用关联关系来替代继 承关系,因此大部分结构型模式都是对象结构型模式。
1. 适配器模式
1.1 定义
适配器模式(Adapter Pattern) :将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。
1.2 结构
- Target:目标抽象类
- Adapter:适配器类
- Adaptee:适配者类
- Client:客户类
对象适配器
类适配器
1.3 时序图
1.4 代码
#include <iostream>
#include "Adapter.h"
#include "Adaptee.h"
#include "Target.h"
using namespace std;
int main(int argc, char *argv[])
{
Adaptee * adaptee = new Adaptee();
Target * tar = new Adapter(adaptee);
tar->request();
return 0;
}
///
// Adapter.h
// Implementation of the Class Adapter
// Created on: 03-十月-2014 17:32:00
// Original author: colin
///
#if !defined(EA_BD766D47_0C69_4131_B7B9_21DF78B1E80D__INCLUDED_)
#define EA_BD766D47_0C69_4131_B7B9_21DF78B1E80D__INCLUDED_
#include "Target.h"
#include "Adaptee.h"
class Adapter : public Target
{
public:
Adapter(Adaptee *adaptee);
virtual ~Adapter();
virtual void request();
private:
Adaptee* m_pAdaptee;
};
#endif // !defined(EA_BD766D47_0C69_4131_B7B9_21DF78B1E80D__INCLUDED_)
///
// Adapter.cpp
// Implementation of the Class Adapter
// Created on: 03-十月-2014 17:32:00
// Original author: colin
///
#include "Adapter.h"
Adapter::Adapter(Adaptee * adaptee){
m_pAdaptee = adaptee;
}
Adapter::~Adapter(){
}
void Adapter::request(){
m_pAdaptee->specificRequest();
}
///
// Adaptee.h
// Implementation of the Class Adaptee
// Created on: 03-十月-2014 17:32:00
// Original author: colin
///
#if !defined(EA_826E6B4F_12BE_4609_A0A3_95BD5E657D36__INCLUDED_)
#define EA_826E6B4F_12BE_4609_A0A3_95BD5E657D36__INCLUDED_
class Adaptee
{
public:
Adaptee();
virtual ~Adaptee();
void specificRequest();
};
#endif // !defined(EA_826E6B4F_12BE_4609_A0A3_95BD5E657D36__INCLUDED_)
运行结果
1.5 适用环境
- 系统需要使用现有的类,而这些类的接口不符合系统的需要。
- 想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。
2. 桥接模式
2.1 定义
桥接模式(Bridge Pattern):将抽象部分与它的实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(Interface)模式。
2.2 结构
- Abstraction:抽象类
- RefinedAbstraction:扩充抽象类
- Implementor:实现类接口
- ConcreteImplementor:具体实现类
2.3 时序图
2.4 代码
#include <iostream>
#include "ConcreteImplementorA.h"
#include "ConcreteImplementorB.h"
#include "RefinedAbstraction.h"
#include "Abstraction.h"
using namespace std;
int main(int argc, char *argv[])
{
Implementor * pImp = new ConcreteImplementorA();
Abstraction * pa = new RefinedAbstraction(pImp);
pa->operation();
Abstraction * pb = new RefinedAbstraction(new ConcreteImplementorB());
pb->operation();
delete pa;
delete pb;
return 0;
}
///
// RefinedAbstraction.h
// Implementation of the Class RefinedAbstraction
// Created on: 03-十月-2014 18:12:43
// Original author: colin
///
#if !defined(EA_4BA5BE7C_DED5_4236_8362_F2988921CFA7__INCLUDED_)
#define EA_4BA5BE7C_DED5_4236_8362_F2988921CFA7__INCLUDED_
#include "Abstraction.h"
class RefinedAbstraction : public Abstraction
{
public:
RefinedAbstraction();
RefinedAbstraction(Implementor* imp);
virtual ~RefinedAbstraction();
virtual void operation();
};
#endif // !defined(EA_4BA5BE7C_DED5_4236_8362_F2988921CFA7__INCLUDED_)
///
// RefinedAbstraction.cpp
// Implementation of the Class RefinedAbstraction
// Created on: 03-十月-2014 18:12:43
// Original author: colin
///
#include "RefinedAbstraction.h"
#include <iostream>
using namespace std;
RefinedAbstraction::RefinedAbstraction(){
}
RefinedAbstraction::RefinedAbstraction(Implementor* imp)
:Abstraction(imp)
{
}
RefinedAbstraction::~RefinedAbstraction(){
}
void RefinedAbstraction::operation(){
cout << "do something else ,and then " << endl;
m_pImp->operationImp();
}
- 运行结果
2.5 适用环境
- 如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立一个关联关系。
- 抽象化角色和实现化角色可以以继承的方式独立扩展而互不影响,在程序运行时可以动态将一个抽象化子类的对象和一个实现化子类的对象进行组合,即系统需要对抽象化角色和实现化角色进行动态耦合。
- 一个类存在两个独立变化的维度,且这两个维度都需要进行扩展。
- 虽然在系统中使用继承是没有问题的,但是由于抽象化角色和具体化角色需要独立变化,设计要求需要独立管理这两者。
- 对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。
适配器模式与桥接模式的联用:
- 桥接模式和适配器模式用于设计的不同阶段,桥接模式用于系统的初步设计,对于存在两个独立变化维度的类可以将其分为抽象化和实现化两个角色,使它们可以分别进行变化;而在初步设计完成之后,当发现系统与已有类无法协同工作时,可以采用适配器模式。但有时候在设计初期也需要考虑适配器模式,特别是那些涉及到大量第三方应用接口的情况。
3. 装饰模式
3.1 定义
装饰模式(Decorator Pattern) :动态地给一个对象增加一些额外的职责(Responsibility),就增加对象功能来说,装饰模式比生成子类实现更为灵活。其别名也可以称为包装器(Wrapper),与适配器模式的别名相同,但它们适用于不同的场合。根据翻译的不同,装饰模式也有人称之为“油漆工模式”,它是一种对象结构型模式。
3.2 结构
- Component: 抽象构件
- ConcreteComponent: 具体构件
- Decorator: 抽象装饰类
- ConcreteDecorator: 具体装饰类
3.3 时序图
3.4 代码
///
// ConcreteComponent.cpp
// Implementation of the Class ConcreteComponent
// Created on: 03-十月-2014 18:53:00
// Original author: colin
///
#include "ConcreteComponent.h"
#include <iostream>
using namespace std;
ConcreteComponent::ConcreteComponent(){
}
ConcreteComponent::~ConcreteComponent(){
}
void ConcreteComponent::operation(){
cout << "ConcreteComponent's normal operation!" << endl;
}
///
// ConcreteDecoratorA.h
// Implementation of the Class ConcreteDecoratorA
// Created on: 03-十月-2014 18:53:00
// Original author: colin
///
#if !defined(EA_6786B68E_DCE4_44c4_B26D_812F0B3C0382__INCLUDED_)
#define EA_6786B68E_DCE4_44c4_B26D_812F0B3C0382__INCLUDED_
#include "Decorator.h"
#include "Component.h"
class ConcreteDecoratorA : public Decorator
{
public:
ConcreteDecoratorA(Component* pcmp);
virtual ~ConcreteDecoratorA();
void addBehavior();
virtual void operation();
};
#endif // !defined(EA_6786B68E_DCE4_44c4_B26D_812F0B3C0382__INCLUDED_)
///
// ConcreteDecoratorA.cpp
// Implementation of the Class ConcreteDecoratorA
// Created on: 03-十月-2014 18:53:00
// Original author: colin
///
#include "ConcreteDecoratorA.h"
#include <iostream>
using namespace std;
ConcreteDecoratorA::ConcreteDecoratorA(Component* pcmp) : Decorator(pcmp){
}
ConcreteDecoratorA::~ConcreteDecoratorA(){
}
void ConcreteDecoratorA::addBehavior(){
cout << "addBehavior AAAA" << endl;
}
void ConcreteDecoratorA::operation(){
Decorator::operation();
addBehavior();
}
- 运行结果
3.5 适用环境
- 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
- 需要动态地给一个对象增加功能,这些功能也可以动态地被撤销。
- 当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。不能采用继承的情况主要有两类:第一类是系统中存在大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长;第二类是因为类定义不能继承(如final类)。
4. 外观模式
4.1 定义
外观模式(Facade Pattern):外部与一个子系统的通信必须通过一个统一的外观对象进行,为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。外观模式又称为门面模式,它是一种对象结构型模式。
4.2 结构
- Facade: 外观角色
- SubSystem:子系统角色
4.3 时序图
4.4 代码
#include <iostream>
#include "Facade.h"
using namespace std;
int main(int argc, char *argv[])
{
Facade fa;
fa.wrapOpration();
return 0;
}
///
// Facade.h
// Implementation of the Class Facade
// Created on: 06-十月-2014 19:10:44
// Original author: colin
///
#if !defined(EA_FD130A87_92A9_4168_9B33_7A925C47AFD5__INCLUDED_)
#define EA_FD130A87_92A9_4168_9B33_7A925C47AFD5__INCLUDED_
#include "SystemC.h"
#include "SystemA.h"
#include "SystemB.h"
class Facade
{
public:
Facade();
virtual ~Facade();
void wrapOpration();
private:
SystemC *m_SystemC;
SystemA *m_SystemA;
SystemB *m_SystemB;
};
#endif // !defined(EA_FD130A87_92A9_4168_9B33_7A925C47AFD5__INCLUDED_)
///
// Facade.cpp
// Implementation of the Class Facade
// Created on: 06-十月-2014 19:10:44
// Original author: colin
///
#include "Facade.h"
Facade::Facade(){
m_SystemA = new SystemA();
m_SystemB = new SystemB();
m_SystemC = new SystemC();
}
Facade::~Facade(){
delete m_SystemA;
delete m_SystemB;
delete m_SystemC;
}
void Facade::wrapOpration(){
m_SystemA->operationA();
m_SystemB->operationB();
m_SystemC->opeartionC();
}
- 运行结果
4.5 适用环境
- 当要为一个复杂子系统提供一个简单接口时可以使用外观模式。该接口可以满足大多数用户的需求,而且用户也可以越过外观类直接访问子系统。
- 客户程序与多个子系统之间存在很大的依赖性。引入外观类将子系统与客户以及其他子系统解耦,可以提高子系统的独立性和可移植性。
- 在层次化结构中,可以使用外观模式定义系统中每一层的入口,层与层之间不直接产生联系,而通过外观类建立联系,降低层之间的耦合度。
5. 享元模式
5.1 定义
享元模式(Flyweight Pattern):运用共享技术有效地支持大量细粒度对象的复用。系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。由于享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻量级模式,它是一种对象结构型模式。
5.2 结构
- Flyweight: 抽象享元类
- ConcreteFlyweight: 具体享元类
- UnsharedConcreteFlyweight: 非共享具体享元类
- FlyweightFactory: 享元工厂类
5.3 时序图
5.4 代码
#include <iostream>
#include "ConcreteFlyweight.h"
#include "FlyweightFactory.h"
#include "Flyweight.h"
using namespace std;
int main(int argc, char *argv[])
{
FlyweightFactory factory;
Flyweight * fw = factory.getFlyweight("one");
fw->operation();
Flyweight * fw2 = factory.getFlyweight("two");
fw2->operation();
//aready exist in pool
Flyweight * fw3 = factory.getFlyweight("one");
fw3->operation();
return 0;
}
///
// FlyweightFactory.cpp
// Implementation of the Class FlyweightFactory
// Created on: 06-十月-2014 20:10:42
// Original author: colin
///
#include "FlyweightFactory.h"
#include "ConcreteFlyweight.h"
#include <iostream>
using namespace std;
FlyweightFactory::FlyweightFactory(){
}
FlyweightFactory::~FlyweightFactory(){
}
Flyweight* FlyweightFactory::getFlyweight(string str){
map<string,Flyweight*>::iterator itr = m_mpFlyweight.find(str);
if(itr == m_mpFlyweight.end())
{
Flyweight * fw = new ConcreteFlyweight(str);
m_mpFlyweight.insert(make_pair(str,fw));
return fw;
}
else
{
cout << "aready in the pool,use the exist one:" << endl;
return itr->second;
}
}
///
// ConcreteFlyweight.h
// Implementation of the Class ConcreteFlyweight
// Created on: 06-十月-2014 20:10:42
// Original author: colin
///
#if !defined(EA_C0AF438E_96E4_46f1_ADEC_308EF16E11D1__INCLUDED_)
#define EA_C0AF438E_96E4_46f1_ADEC_308EF16E11D1__INCLUDED_
#include "Flyweight.h"
#include <string>
using namespace std;
class ConcreteFlyweight : public Flyweight
{
public:
ConcreteFlyweight(string str);
virtual ~ConcreteFlyweight();
virtual void operation();
private:
string intrinsicState;
};
#endif // !defined(EA_C0AF438E_96E4_46f1_ADEC_308EF16E11D1__INCLUDED_)
///
// ConcreteFlyweight.cpp
// Implementation of the Class ConcreteFlyweight
// Created on: 06-十月-2014 20:10:42
// Original author: colin
///
#include "ConcreteFlyweight.h"
#include <iostream>
using namespace std;
ConcreteFlyweight::ConcreteFlyweight(string str){
intrinsicState = str;
}
ConcreteFlyweight::~ConcreteFlyweight(){
}
void ConcreteFlyweight::operation(){
cout << "Flyweight[" << intrinsicState << "] do operation." << endl;
}
- 运行结果
5.5 适用环境
- 一个系统有大量相同或者相似的对象,由于这类对象的大量使用,造成内存的大量耗费。
- 对象的大部分状态都可以外部化,可以将这些外部状态传入对象中。
- 使用享元模式需要维护一个存储享元对象的享元池,而这需要耗费资源,因此,应当在多次重复使用享元对象时才值得使用享元模式。
6. 代理模式
6.1 定义
代理模式(Proxy Pattern) :给某一个对象提供一个代 理,并由代理对象控制对原对象的引用。代理模式的英 文叫做Proxy或Surrogate,它是一种对象结构型模式。
6.2 结构
- Subject: 抽象主题角色
- Proxy: 代理主题角色
- RealSubject: 真实主题角色
6.3 时序图
6.4 代码
#include <iostream>
#include "RealSubject.h"
#include "Proxy.h"
using namespace std;
int main(int argc, char *argv[])
{
Proxy proxy;
proxy.request();
return 0;
}
///
// Proxy.h
// Implementation of the Class Proxy
// Created on: 07-十月-2014 16:57:54
// Original author: colin
///
#if !defined(EA_56011290_0413_40c6_9132_63EE89B023FD__INCLUDED_)
#define EA_56011290_0413_40c6_9132_63EE89B023FD__INCLUDED_
#include "RealSubject.h"
#include "Subject.h"
class Proxy : public Subject
{
public:
Proxy();
virtual ~Proxy();
void request();
private:
void afterRequest();
void preRequest();
RealSubject *m_pRealSubject;
};
#endif // !defined(EA_56011290_0413_40c6_9132_63EE89B023FD__INCLUDED_)
///
// Proxy.cpp
// Implementation of the Class Proxy
// Created on: 07-十月-2014 16:57:54
// Original author: colin
///
#include "Proxy.h"
#include <iostream>
using namespace std;
Proxy::Proxy(){
//有人觉得 RealSubject对象的创建应该是在main中实现;我认为RealSubject应该
//对用户是透明的,用户所面对的接口都是通过代理的;这样才是真正的代理;
m_pRealSubject = new RealSubject();
}
Proxy::~Proxy(){
delete m_pRealSubject;
}
void Proxy::afterRequest(){
cout << "Proxy::afterRequest" << endl;
}
void Proxy::preRequest(){
cout << "Proxy::preRequest" << endl;
}
void Proxy::request(){
preRequest();
m_pRealSubject->request();
afterRequest();
}
- 运行结果
6.5 适用环境
- 远程(Remote)代理:为一个位于不同的地址空间的对象提供一个本地 的代理对象,这个不同的地址空间可以是在同一台主机中,也可是在 另一台主机中,远程代理又叫做大使(Ambassador)。
- 虚拟(Virtual)代理:如果需要创建一个资源消耗较大的对象,先创建一个消耗相对较小的对象来表示,真实对象只在需要时才会被真正创建。
- Copy-on-Write代理:它是虚拟代理的一种,把复制(克隆)操作延迟 到只有在客户端真正需要时才执行。一般来说,对象的深克隆是一个 开销较大的操作,Copy-on-Write代理可以让这个操作延迟,只有对象被用到的时候才被克隆。
- 保护(Protect or Access)代理:控制对一个对象的访问,可以给不同的用户提供不同级别的使用权限。
- 缓冲(Cache)代理:为某一个目标操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果。
- 防火墙(Firewall)代理:保护目标不让恶意用户接近。
- 同步化(Synchronization)代理:使几个用户能够同时使用一个对象而没有冲突。
- 智能引用(Smart Reference)代理:当一个对象被引用时,提供一些额外的操作,如将此对象被调用的次数记录下来等。