设计模式概览——结构型模式

上篇文章“设计模式概览——创建型模式”整理了创建型模式的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();
}

抽象主题角色声明了真实主题和代理主题的共同接口;代理主题角色内部包含对真实主题的引用,从而可以在任何时候操作真实主题对象;真实主题角色中实现了真实的业务操作。用户可以通过代理主题角色间接调用真实主题角色中定义的方法。代理模式可以在一定程度上降低系统的耦合度。

常见的代理有:远程代理、虚拟代理、保护代理、防火墙待、智能引用代理等。
 

发布了57 篇原创文章 · 获赞 58 · 访问量 13万+

猜你喜欢

转载自blog.csdn.net/DeliaPu/article/details/104504086