结构型模式涉及到如何组合类和对象以获得更大的结构。结构型类模式采用继承机制来组合接口或实现;结构型对象模式不是对接口或实现进行组合,而是描述了如何对一些对象进行组合,从而实现新功能的一些方法。因为可以在运行时刻改变对象组合关系,所以对象组合方式具有更大的灵活性。
1. Adapter类/对象模式
作用:
将一个类的接口转换成客户希望的另外一个接口,Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
UML示意图:
1)采用继承原有接口类的方式
2)采用组合原有接口类的方式
解析:
Adapter模式起始就是把完成同样一个功能但是接口不能兼容的类桥接在一起使之可以在一起工作,这个模式使得复用旧的接口称为可能。
实现:
1.采用继承原有接口类的方法 //需要被Adapt的类 class Target { public: Target(){} virtual ~Target(){} virtual void Request() { cout<<"Target::Request"<<endl; } }; //与被Adapt对象提供不兼容接口的类 class Adaptee { public: Adaptee(){} ~Adaptee(){} void SpecificRequest() { cout<<"Adaptee::SpecificRequest"<<endl; } }; //进行Adapt的类,采用继承原有接口类的方式 class Adapter:public Target,private Adaptee { public: Adapter(){} ~Adapter(){} void Request() { this->SpecificRequest(); } }; int main() { Target* adt = new Adapter(); adt->Request(); return 0; } 2. 采用组合原有接口类的方法 //需要被Adapt的类 class Target { public: Target(){} virtual ~Target(){} virtual void Request() { cout<<"Target::Request"<<endl; } }; //与被Adapt对象提供不兼容接口的类 class Adaptee { public: Adaptee(){} ~Adaptee(){} void SpecificRequest() { cout<<"Adaptee::SpecificRequest"<<endl; } }; //进行Adapt的类,采用聚合原有接口类的方式 class Adapter:public Target { public: Adapter(Adaptee* ade) { this->_ade = ade; } ~Adapter(){} void Request() { _ade->SpecificRequest(); } private: Adaptee* _ade; };
2. Bridge——对象结构型模式
作用:
将抽象部分与实现部分分离,使他们都可以独立的变化
UML结构图:
抽象基类:
1)Abstraction 某个抽象类,它的实现方式由 Implementor完成
2)Implementor 实现类的抽象基类,定义了实现Abstraction的基本操作,而它的派生类实现这些接口
接口函数:
Implementor::OperationImpl 实定义了为实现Abstraction需要的基本操作,由Implementor的派生类实现之,而在Abstraction::Operation函数中根据不同的指针多态调用这个函数
解析:
bridge模式用于将表示和实现解耦,两者可以独立的变化。在Abstraction类中维护一个Implementor类指针,需要采用不同的方式的时候只需要传入不同的Implementor派生类就可以了。
Bridge 的实现方式其实和 Builder 十分的相近,可以这么说:本质上是一样的,只是封装的东西不一样.两者的实现都有如下的共同点:
抽象出来一个基类,这个基类里面定义了共有的一些行为,形成接口函数(对接口编程而不是对实现编程),这个接口函数在 Builder 中是 BuildePart 函数在 Bridge 中是 OperationImpl 函数;
其次,聚合一个基类的指针,如 Builder 模式中 Director 类聚合了一个 Builder 基类的指针,而 Brige 模式中 Abstraction 类聚合了一个 Implementor 基类的指针(优先采用聚合而不是继承);
而在使用的时候, 都把对这个类的使用封装在一个函数中, 在 Bridge 中是封装在 Director::Construct函数中, 因为装配不同部分的过程是一致的,而在 Bridge 模式中则是封装在 Abstraction::Operation 函数中,在这个函数中调用对应的 Implementor::OperationImp 函数.
就两个模式而言,Builder 封装了不同的生成组成部分的方式, 而 Bridge封装了不同的实现方式.
3. Composite——对象结构型模式
作用:
将对象组合成树形结构以表示“部分-整体”的层次结构,Composite使得用户对单个对象和组合对象的使用具有一致性。
UML结构图:
抽象基类:
Component: 为组合中的对象声明接口,声明了类共有接口的缺省行为(如这里的Add,Remove,GetChild函数),声明一个接口函数可以访问Component的子组件
接口函数:
1)Component::Operation 定义了各个组件共有的行为接口,由各个组件具体实现
2)Component::Add 添加一个子组件
3)Component::Remove 删除一个子组件
4)Component::GetChild 获得子组件的指针
解析:
Component模式为解决组件之间的递归组合提供了解决的方法,它主要分为两个派生类,其中的Leaf是叶子节点,也就是不含有子组件的节点,而Composite是含有子组件的节点。
实现:
//组合中的抽象基类 class Component { public: Component(){} virtual ~Component(){} //纯虚函数,只提供接口,没有默认的实现 virtual void Operation()=0; //虚函数,提供接口,有默认的实现就是什么都不做 virtual void Add(Component* pChild){} virtual void Remove(Component* pChild){} virtual Component* GetChild(int nIndex) { return NULL; } }; //派生自Component,是其中的叶子组件的基类 class Leaf:public Component { public: Leaf(){} virtual ~Leaf(){} virtual void Operation() { cout<<"Operation by Leaf"<<endl; } }; //派生自Component,是其中含有子间的组件的基类 class Composite:public Component { public: Composite(){} virtual ~Composite() { list<Component*>::iterator iter1,iter2,temp; for(iter1=m_ListOfComponent.begin(),iter2=m_ListOfComponent.end();iter1!=iter2;) { temp = iter1; ++iter1; delete(*temp); } } virtual void Operation() { cout<<"Operation by Conposite"<<endl; list<Component*>::iterator iter1,iter2; for(iter1=m_ListOfComponent.begin(),iter2=m_ListOfComponent.end(); iter1!=iter2;++iter1) (*iter1)->Operation(); } virtual void Add(Component* pChild) { m_ListOfComponent.push_back(pChild);} virtual void Remove(Component* pChild) { list<Component*>::iterator iter; iter = find(m_ListOfComponent.begin(),m_ListOfComponent.end(),pChild); if(m_ListOfComponent.end()!=iter) { m_ListOfComponent.erase(iter); } } virtual Component* GetChild(int nIndex) { if(nIndex<=0||nIndex>m_ListOfComponent.size()) return NULL; list<Component*>::iterator iter1,iter2; int i; for(i=1,iter1=m_ListOfComponent.begin(),iter2=m_ListOfComponent.end(); iter1!=iter2;++iter1,++i) { if(i==nIndex) break; } return *iter1; } private: //采用list容器去保存子组件 list<Component*> m_ListOfComponent; }; int main() { Leaf* pLeaf1 = new Leaf(); Leaf* pLeaf2 = new Leaf(); Composite* pComposite = new Composite; pComposite->Add(pLeaf1); pComposite->Add(pLeaf2); pComposite->Operation(); pComposite->GetChild(2)->Operation(); delete pComposite; return 0; }
4. Decorator——对象结构型模式
作用:
动态的给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更加灵活。
UML结构图:
抽象基类:
1)Component 定义一个对象接口,可以为这个接口动态的添加职责
2)Decorator 维持一个指向Component的指针,并且有一个和Component一致的接口函数
接口函数:
Component::Operation 这个接口函数由Component声明,因此Component的派生类都需要实现,可以在这个接口函数的基础上给它动态添加职责。
解析:
Decorator的派生类可以为ConcreteComponent类的对象动态的添加职责。具体实现为:
首先初始化一个ConcreteComponent类的对象(被装饰者),采用这个对象去生成一个Decorator对象,之后对Operation函数的调用则是对这个Decorator对象成员函数的多态调用。这里的实现要点是Decorator类和ConcreteComponent类都继承自Component,二者的接口函数是一样的;其次,Decorator维护了一个指向Component的指针,从而可以实现对Component::Operation函数的动态调用。
实现:
//抽象基类,定义一个对象接口,可以为这个接口动态的添加职责. class Component { public: Component(){} virtual ~Component(){} //纯虚函数,由派生类实现 virtual void Operation()=0; }; //抽象基类,维护一个指向Component对象的指针 class Decorator:public Component { public: Decorator(Component* com) { this->_com = com; } virtual ~Decorator() { delete _com; } void Operation(){} protected: Component* _com; }; //派生自Component,在这里表示需要给它动态添加职责的类 class ConcreteComponent:public Component { public: ConcreteComponent(){} ~ConcreteComponent(){} void Operation() { cout<<"ConcreteComponent operator.."<<endl; } }; //派生自Decorator,这里代表为ConcreateComponent动态添加职责的类 class ConcreteDecorator:public Decorator { public: ConcreteDecorator(Component* com):Decorator(com){} virtual ~ConcreteDecorator(){} virtual void Operation() { _com->Operation(); this->AddedBehavior(); } void AddedBehavior() { cout<<"ConcreteDecorator::AddedBehavior..."<<endl; } }; int main(){ //初始化一个 Component 对象 Component* com = new ConcreteComponent(); //采用这个Component对象去初始化一个Decorator对象, //这样就可以为这个Component对象动态添加职责 Decorator* dec = new ConcreteDecorator(com); dec->Operation(); delete dec; return 0; }
5. Proxy——对象结构型模式
目的:
为其他对象提供一种代理以控制对这个对象的访问
UML结构图:
抽象基类:
1)Subject 定义了Proxy和RealSubject的公有接口,这样就可以在任何需要用到RealSubject的地方都使用Proxy了
解析:
Proxy起始是基于这样一种经常被使用的技术——某个对象直到它真正被使用到的时候才被初始化,在没有使用到的时候就暂时用Proxy作一个占位符。这个模式实现的要点是Proxy和RealSubject都继承自Subject,这样保证了两个的接口是一致的。
实现:
//定义了 Proxy 和 RealSubject 的公有接口, //这样就可以在任何需要使用到RealSubject的地方都使用Proxy class Subject { public: Subject(){} virtual ~Subject(){} virtual void Request()=0; }; //真正使用的实体 class RealSubject:public Subject { public: RealSubject() { cout<<"construction of RealSubject"<<endl; } virtual ~RealSubject(){} virtual void Request() { cout<<"Request by RealSubject"<<endl; } }; //代理类,含有一个指向RealSubject对象的指针 class Proxy:public Subject { public: Proxy():m_pRealSubject(NULL) { cout<<"Construction a Proxy"<<endl; } virtual ~Proxy() { delete m_pRealSubject; m_pRealSubject = NULL; } virtual void Request() { //需要使用Real Subject的时候才去初始化 if(NULL==m_pRealSubject) { cout<<"Realquest by Proxy"<<endl; m_pRealSubject = new RealSubject(); } m_pRealSubject->Request(); } private: RealSubject* m_pRealSubject; }; int main() { Subject* pProxy = new Proxy(); pProxy->Request(); delete pProxy; return 0; }
6. Facade——对象结构型模式
作用:
为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
UML结构图:
解析:
Facade模式对客户屏蔽了子系统组件,因而减少了客户处理的对象的数目并使得子系统使用起来更加方便;实现了子系统与客户之间的松耦合关系,而子系统内部的功能组件往往是紧耦合的,松耦合关系使得子系统的组件变化不会影响到它的客户
7. Flyweight——对象结构型模式
作用:
运用共享技术有效的支持大量细粒度对象。
UML结构:
成员:
Flyweight 描述一个接口,通过这个接口flyweight可以接受并作用于外部状态
ConcreteFlyweight 实现Flyweight接口,并为内部状态(如果有的话)增加存储空间,ConcreteFlyweight对象必须是可共享的,它所存储的状态必须是内部的;即,它必须独立于ConcreteFlyweight对象的场景。
UnsharedConcreteFlyweight 并非所有的Flyweight子类都需要被共享,Flyweight接口使共享称为可能,但它并不强制共享。在Flyweight对象接口的某些层次,UnsharedConcreteFlyweight对象通常将ConcreteFlyweight对象作为子节点。
FlyweightFactory 创建并管理flyweight对象。确保合理的共享flyweight,当用户请求一个flyweight时,FlyweightFactory对象提供一个已创建的实例或者创建一个(如果不存在的话)。
解析:
程序中可能会使用到大量的对象(比如一个文档中有N多个字符),如果对每个对象都单独申请空间进行构造,则会带来很大的内存资源开销,此时可以考虑抽象出来这些对象的相同的部分和相异的部分,相同的部分作为公共的对象,由各个对象共享(即每个对象拥有公共对象的引用或指针)。
比如文档中有许多个字符,但这些字符都是属于[A-Za-z]的范围之内,则将[A-Za-z]范围内的字符(公共部分)构造对象,存放在共享池中,文档中的各个字符共享相对应的共享对象池中的对象。