上篇文章“设计模式概览——创建型模式”整理了创建型模式的5种类型,今天我们接着来整理一下结构型模式。
结构型模式旨在描述如何将类或对象结合在一起形成更大的结构。类结构型模式关注类的组合,一般只存在继承关系和实现关系;对象结构型模式关心类与对象的组合,通过关联关系使得在一个类中定义另一个类的实例对象,并实现对该对象方法的调用(我们现在开发的系统里就有不少这种应用)。大部分结构型模式都是对象结构型模式。
结构型模式总共有7种具体的模式,分别是适配器模式、桥接模式、组合模式、装饰模式、外观模式、享元模式、代理模式。
下面我们就来看几种结构型模式的定义和简单描述。
1. 适配器模式(Adapter Pattern)
适配器模式的作用是将一个形式的接口转换成另一个形式的接口,使接口不兼容的类可以一起工作,因此适配器也叫包装器。适配器模式可以作为类结构模式,也可以作为对象结构模式。
适配器模式包含4个角色:
(1) 目标抽象类Target
(2) 适配器类Adapter
(3) 适配者类Adaptee
(4) 客户类Client,或用户类,即调用者。
示例代码:
#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
// Definition of the Class Adapter
///
#include "Target.h"
#include "Adaptee.h"
class Adapter : public Target
{
public:
Adapter(Adaptee *adaptee);
virtual ~Adapter();
virtual void request();
private:
Adaptee* m_pAdaptee;
};
///
// Adapter.cpp
// Implementation of the Class Adapter
///
#include "Adapter.h"
Adapter::Adapter(Adaptee * adaptee)
{
m_pAdaptee = adaptee;
}
Adapter::~Adapter()
{
}
void Adapter::request()
{
m_pAdaptee->specificRequest();
}
///
// Adaptee.h
// Definition of the Class Adaptee
///
class Adaptee
{
public:
Adaptee();
virtual ~Adaptee();
void specificRequest();
};
适配器模式的适用场景:
(1) 系统需要使用现有的类,而这些类的接口不符合系统的需要;
(2) 希望建立一个可以重复使用的类,用于将彼此之间没有太大关联的类组织起来一起工作。
2. 桥接模式(Bridge Pattern)
桥接模式是将抽象部分与其实现部分分离,使两者可以独立变化,又称为柄体(Handle and Body)模式或接口(Interface)模式。
桥接模式包含四种角色:
(1) 抽象类Abstraction
(2) 扩充抽象类RefinedAbstraction
(3) 实现类接口Implementor
(4) 具体实现类ConcreteImplementor
示例代码:
#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
// Definition of the Class RefinedAbstraction
///
#include "Abstraction.h"
class RefinedAbstraction : public Abstraction
{
public:
RefinedAbstraction();
RefinedAbstraction(Implementor* imp);
virtual ~RefinedAbstraction();
virtual void operation();
};
///
// RefinedAbstraction.cpp
// Implementation of the Class RefinedAbstraction
///
#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();
}
桥接模式理解起来有一定的难度。该模式的要点在于如何将抽象化和实现化脱耦,使两者可以独立地变化。桥接模式中的脱耦,是指在一个软件系统的抽象化和实现化之间,使用关联关系而不是继承关系,从而使两者的变化互不干扰。想象一个跨平台视频播放器,可以应用在不同的操作系统如Windows、Linux、iOS上面播放不同格式的视频文件,如MP4、AVI、WMV等。
3. 装饰模式(Decorator Pattern)
装饰模式是动态地给一个对象增加一些额外的职责,在增加对象功能方面,装饰模式比生成子类更加灵活。装饰模式与适配器模式比较像,但它们适用于不同的场景。
装饰模式包含4个角色:
(1) 抽象构件Component
(2) 具体构件ConcreteComponent
(3) 抽象装饰类Decorator
(4) 具体装饰类ConcreteDecorator
示例代码:
///
// ConcreteComponent.cpp
// Implementation of the Class ConcreteComponent
///
#include "ConcreteComponent.h"
#include <iostream>
using namespace std;
ConcreteComponent::ConcreteComponent()
{
}
ConcreteComponent::~ConcreteComponent()
{
}
void ConcreteComponent::operation()
{
cout << "ConcreteComponent's normal operation!" << endl;
}
///
// ConcreteDecoratorA.h
// Definition of the Class ConcreteDecoratorA
///
#include "Decorator.h"
#include "Component.h"
class ConcreteDecoratorA : public Decorator
{
public:
ConcreteDecoratorA(Component* pcmp);
virtual ~ConcreteDecoratorA();
void addBehavior();
virtual void operation();
};
///
// ConcreteDecoratorA.cpp
// Implementation of the Class ConcreteDecoratorA
///
#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();
}
关联关系与继承关系相比,优势在于不会破坏类的封装性,是一种松耦合关系,特别适用于系统在维护阶段增加行为。装饰者模式可以动态地给一个对象附加更多的行为,在不创造更多子类的情况下,实现对象功能的扩展。
4. 外观模式(Facade Pattern)
外观模式又称为门面模式,它为系统中的一组子系统提供了一个一致的高层接口(外观对象),外部与这些子系统的通信必须通过这个外观对象进行。
外观模式包含2个角色:
(1) 外观角色Facade
(2) 子系统角色SubSystem
示例代码:
#include <iostream>
#include "Facade.h"
using namespace std;
int main(int argc, char *argv[])
{
Facade fa;
fa.wrapOpration();
return 0;
}
///
// Facade.h
// Definition of the Class Facade
///
#ifndef __FACADE_H__
#define __FACADE_H__
#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
///
// Facade.cpp
// Implementation of the Class Facade
///
#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();
}
外观模式通过引入一个外观对象,为子系统的访问提供了一个简单而单一的入口,从而降低原有系统的复杂度,降低主调模块与子系统类的耦合度,是“迪米特法则”的一种体现。主调模块无须关心各个子系统的工作细节,通过外观角色即可调用相应的功能。
5. 享元模式(Flaywight Pattern)
享元模式是利用共享技术支持大量细粒度对象的复用。系统只使用少量的对象,而这些对象很相似,状态变化很小,可以实现对象的多次复用。由于享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻量级模式。
享元模式中,可以共享的内容成为内部状态(Intrinsic State),而那些需要外部环境来设置的不能共享的内容称为外部状态(Extrinsic State)。
享元模式包含4个角色:
(1) 抽象享元类Flyweight
(2) 具体享元类ConcreteFlyweight
(3) 非共享具体享元类UnsharedConcreteFlyweight
(4) 享元工厂类FltyweightFactory
示例代码:
#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
///
#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
// Definition of the Class ConcreteFlyweight
///
#ifndef __CONCRET_FLAYWEIGHT_H__
#define __CONCRET_FLAYWEIGHT_H__
#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
///
// ConcreteFlyweight.cpp
// Implementation of the Class ConcreteFlyweight
///
#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;
}
享元模式中通常会出现工厂模式,从上面代码就可看出,享元工厂用来维护一个享元池,用于存储具有相同内部状态的享元对象。用于需要对象时,首先从享元池中获取,如果享元池中不存在,则创建一个新的享元对象返回给用户,并在享元池中保存该新增的对象。
6. 代理模式(Proxy Pattern)
当用户不想或者不能直接引用一个对象时,可以通过一个称之为“代理”的第三者来实现间接应用。通过引入一个新的对象来实现对真实对象的操作,或者将新引入的对象作为真实对象的一个替身,这种实现机制即为代理模式。
代理模式包含3个角色:
(1) 抽象角色Subject
(2) 代理角色Proxy
(3) 真实角色 RealSubject
示例代码:
#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
// Definition of the Class Proxy
///
#ifndef __PROXY_H__
#define __PROXY_H__
#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
///
// Proxy.cpp
// Implementation of the Class Proxy
///
#include "Proxy.h"
#include <iostream>
using namespace std;
Proxy::Proxy()
{
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();
}
抽象主题角色声明了真实主题和代理主题的共同接口;代理主题角色内部包含对真实主题的引用,从而可以在任何时候操作真实主题对象;真实主题角色中实现了真实的业务操作。用户可以通过代理主题角色间接调用真实主题角色中定义的方法。代理模式可以在一定程度上降低系统的耦合度。
常见的代理有:远程代理、虚拟代理、保护代理、防火墙待、智能引用代理等。