設計模式概覽——結構型模式

上篇文章“設計模式概覽——創建型模式”整理了創建型模式的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();
}

抽象主題角色聲明瞭真實主題和代理主題的共同接口;代理主題角色內部包含對真實主題的引用,從而可以在任何時候操作真實主題對象;真實主題角色中實現了真實的業務操作。用戶可以通過代理主題角色間接調用真實主題角色中定義的方法。代理模式可以在一定程度上降低系統的耦合度。

常見的代理有:遠程代理、虛擬代理、保護代理、防火牆待、智能引用代理等。
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章