设计模式4  结构型模式


目录

代理模式
装饰器
外观模式
适配器模式


代理模式,美国,韩国代理购物

chunli@linux:~$ cat main.cpp 
#include<iostream>
using namespace std;

class Item	//商品
{
public:
	Item(string kind ,bool fact)
	{
		this->kind = kind;
		this->fact = fact;
	}
	string getKind()
	{
		return kind;
	}
	bool getFact()
	{
		return fact;
	}
private:
	string kind ;
	bool fact;
};

class Shopping 		//抽象的购物方式
{
public:
	virtual void buy(Item *it)  =0;
};

class KoreaShopping:public Shopping  //Korea购物
{
public:
	virtual void buy(Item *it)
	{
		cout << "去Korea 买了" << it->getKind() << endl;
	}
};

class USAShopping:public Shopping   //USA购物
{
public:
	virtual void buy(Item *it)
	{
		cout << "去USA 买了" << it->getKind() << endl;
	}
};


int main()
{
	Item it_1("Nike鞋",true);
	if(it_1.getFact() == true)	//辨别产品真假
	{
		cout << "发现真货" << endl;
		Shopping *koreaShopping = new KoreaShopping;
		koreaShopping->buy(&it_1);//代理
		cout << "过安检" << endl;
	}
	else
	{
		cout << "假货,不要买" << endl;
	}
	
	Item it_2("英语证书",false);


	


	return 0;
}
chunli@linux:~$ g++ main.cpp  -Wall && ./a.out 
发现真货
去Korea 买了Nike鞋
过安检
chunli@linux:~$


代理模式,海外代理韩国与美国

chunli@linux:~$ cat main.cpp 
#include<iostream>
using namespace std;

class Item	//商品
{
public:
	Item(string kind ,bool fact)
	{
		this->kind = kind;
		this->fact = fact;
	}
	string getKind()
	{
		return kind;
	}
	bool getFact()
	{
		return fact;
	}
private:
	string kind ;
	bool fact;
};

class Shopping 		//抽象的购物方式
{
public:
	virtual void buy(Item *it)  =0;
};

class KoreaShopping:public Shopping  //Korea购物
{
public:
	virtual void buy(Item *it)
	{
		cout << "去Korea 买了" << it->getKind() << endl;
	}
};

class USAShopping:public Shopping   //USA购物
{
public:
	virtual void buy(Item *it)
	{
		cout << "去USA 买了" << it->getKind() << endl;
	}
};

class OverseaProxy:public Shopping
{
public:
	OverseaProxy(Shopping *shopping)
	{
		this->shopping =  shopping;
	}
	virtual void buy(Item *it) 
	{
		//购买之前............
		if(it->getFact() == false)
		{
			cout << "发现假货,不要购买" << endl;
			return ;
		}
		//开始购买
		shopping->buy(it);
		//购买之后
		cout << "通过安检,后买成功!" << endl;
	}

private:
	Shopping *shopping;
};

int main()
{
	Shopping *usaShopping 	= new USAShopping;
	Shopping *overseaProxy 	= new OverseaProxy(usaShopping);
	
	Item it1("英语证书",false);	overseaProxy->buy(&it1);
	Item it2("Dell 服务器",true);	overseaProxy->buy(&it2);

	return 0;
}
chunli@linux:~$ g++ main.cpp  -Wall && ./a.out 
发现假货,不要购买
去USA 买了Dell 服务器
通过安检,后买成功!
chunli@linux:~$

看图:

wKioL1g9UpTheNjJAAGIHiBP2T8316.png

wKiom1g9UpXz7aWkAAG7ORCCMMY994.png

  subject(抽象主题角色):真实主题与代理主题的共同接口。 

  RealSubject(真实主题角色):定义了代理角色所代表的真实对象。  

  Proxy(代理主题角色): 含有对真实主题角色的引用,代理角色通常在

将客户端调用传递给真是主题对象之前或者之后执行某些操作,而不是单纯返

回真实的对象。 


优点: 

       (1) 能够协调调用者和被调用者,在一定程度上降低了系统的耦合度。 

       (2) 客户端可以针对抽象主题角色进行编程,增加和更换代理类无须修改源

代码,符合开闭原则,系统具有较好的灵活性和可扩展性。 

  

缺点: 

       (1) 代理实现较为复杂。


---------------------------------------------------------------------




装饰器:把手机裸机 装饰成有贴膜的手机

chunli@linux:~$ cat main.cpp 
#include<iostream>
using namespace std;

class Phone 
{
public:
	virtual void show() = 0;
};

class iPhone:public Phone
{
public:
	virtual void show()
	{
		cout << "秀出了iPhone"<< endl;
	}
};

class Mi:public Phone
{
public:
	virtual void show()
	{
		cout << "秀出了 小米"<< endl;
	}
};

//抽象装饰器
class Decorator:public Phone
{
public:
	Decorator(Phone *phone)
	{
		this->phone = phone;
	}
	virtual void show() = 0;
protected:
	Phone *phone;//拥有一个手机的父类指针
};

//贴膜装饰器
class MoDecorator:public Decorator
{
public:
	MoDecorator(Phone *phone):Decorator(phone)
	{
	}
	virtual void show()
	{
		this->phone->show();
		this->mo();
	}
	void mo()
	{
		cout << "手机 贴膜了 " << endl;
	}
};

int main()
{
	Phone *phone  = new iPhone;	//创建一个裸机
	phone->show();//裸机 show()
	cout << "---------------" <<endl;
	Phone *mophone = new MoDecorator(phone);
	mophone->show();

	return 0;
}
chunli@linux:~$ g++ main.cpp  -Wall && ./a.out 
秀出了iPhone
---------------
秀出了iPhone
手机 贴膜了 
chunli@linux:~$


装饰器,在贴膜的手机,加壳

chunli@linux:~$ g++ main.cpp  -Wall && ./a.out 
秀出了iPhone
---------------
秀出了iPhone
手机 贴膜了 
---------------
秀出了iPhone
手机 贴膜了 
手机 加壳了 
chunli@linux:~$ 
chunli@linux:~$ cat main.cpp 
#include<iostream>
using namespace std;

class Phone 
{
public:
	virtual void show() = 0;
};

class iPhone:public Phone
{
public:
	virtual void show()
	{
		cout << "秀出了iPhone"<< endl;
	}
};

class Mi:public Phone
{
public:
	virtual void show()
	{
		cout << "秀出了 小米"<< endl;
	}
};

//抽象装饰器
class Decorator:public Phone
{
public:
	Decorator(Phone *phone)
	{
		this->phone = phone;
	}
	virtual void show() = 0;
protected:
	Phone *phone;//拥有一个手机的父类指针
};

//贴膜装饰器
class MoDecorator:public Decorator
{
public:
	MoDecorator(Phone *phone):Decorator(phone)
	{
	}
	virtual void show()
	{
		this->phone->show();
		this->mo();
	}
	void mo()
	{
		cout << "手机 贴膜了 " << endl;
	}
};

//手机壳 装饰器
class ShellDecorator:public Decorator
{
public:
	ShellDecorator(Phone *phone):Decorator(phone)
	{
	}
	virtual void show()
	{
		this->phone->show();
		this->shell();
	}
	void shell()
	{
		cout << "手机 加壳了 " << endl;
	}
};

int main()
{
	Phone *phone  = new iPhone;	//创建一个裸机
	phone->show();//裸机 show()
	cout << "---------------" <<endl;
	Phone *mophone = new MoDecorator(phone);
	mophone->show();
	cout << "---------------" <<endl;
	Phone *shellPhone = new ShellDecorator(mophone);
	shellPhone->show();

	return 0;
}
chunli@linux:~$ g++ main.cpp  -Wall && ./a.out 
秀出了iPhone
---------------
秀出了iPhone
手机 贴膜了 
---------------
秀出了iPhone
手机 贴膜了 
手机 加壳了 
chunli@linux:~$



看图

wKiom1g9U0PRBbWDAAMJezcP_TE177.png


  Component(抽象构件): 它是具体构件和抽象装饰类的共同父类,声

明了在具体构件中实现的业务方法,它的引入可以使客户端以一致的方式处理

未被装饰的对象以及装饰之后的对象,实现客户端的透明操作。 

  ConcreteComponent(具体构件): 它是抽象构件类的子类,用于定

义具体的构件对象,实现了在抽象构件中声明的方法,装饰器可以给它增加额

外的职责(方法)。 

  Decorator(抽象装饰类): 它也是抽象构件类的子类,用于给具体构件

增加职责,但是具体职责在其子类中实现。它维护一个指向抽象构件对象的引

用,通过该引用可以调用装饰之前构件对象的方法,并通过其子类扩展该方法,

以达到装饰的目的。 

  ConcreteDecorator(具体装饰类):它是抽象装饰类的子类,负责向

构件添加新的职责。每一个具体装饰类都定义了一些新的行为,它可以调用在

抽象装饰类中定义的方法,并可以增加新的方法用以扩充对象的行为。 




4.2.3 装饰模式的优缺点 

优点: 

(1) 对于扩展一个对象的功能,装饰模式比继承更加灵活性,不会导致类的个数

急剧增加。 

(2)  可以通过一种动态的方式来扩展一个对象的功能,从而实现不同的行为。 

(3)  可以对一个对象进行多次装饰。 

(4) 具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构

件类和具体装饰类,原有类库代码无须改变,符合“开闭原则”。 

缺点: 

(1) 使用装饰模式进行系统设计时将产生很多小对象,大量小对象的产生势必会

占用更多的系统资源,影响程序的性能。 



外观模式: 演示:为了调用AB方法,需要显式的调用AB

chunli@linux:~$ cat main.cpp 
#include<iostream>
using namespace std;

class SysA
{
public:
	void operationA()
	{
		cout << "A........" << endl;
	}
};

class SysB
{
public:
	void operationB()
	{
		cout << "B........" << endl;
	}
};

class SysC
{
public:
	void operationC()
	{
		cout << "C........" << endl;
	}
};
class SysD
{
public:
	void operationD()
	{
		cout << "D........" << endl;
	}
};


int main()
{
	SysA sysa;	sysa.operationA();
	SysB sysb;	sysb.operationB();

	return 0;
}
chunli@linux:~$ g++ main.cpp  && ./a.out 
A........
B........
chunli@linux:~$


现在只需要通过外观访问:打包组合起来

chunli@linux:~$ cat main.cpp 
#include<iostream>
using namespace std;

class SysA
{
public:
	void operationA()
	{
		cout << "A........" << endl;
	}
};

class SysB
{
public:
	void operationB()
	{
		cout << "B........" << endl;
	}
};

class SysC
{
public:
	void operationC()
	{
		cout << "C........" << endl;
	}
};
class SysD
{
public:
	void operationD()
	{
		cout << "D........" << endl;
	}
};

class Facade
{
public:
	void methodOne()
	{
		sysa.operationA();
		sysb.operationB();
		
	}

	void methodTwo()
	{
		sysc.operationC();
		sysd.operationD();
		
	}
private:
	SysA sysa;
	SysB sysb;
	SysC sysc;
	SysD sysd;
};

int main()
{
	Facade	face;	face.methodOne();
	return 0;
}
chunli@linux:~$ g++ main.cpp  && ./a.out 
A........
B........
chunli@linux:~$


适配器模式



手机充电需要使用5V电压,

创建一个适配器,将220V电压转换成5V

chunli@linux:~$ cat main.cpp 
#include <iostream>

using namespace std;
class V5
{
public:
	virtual void useV5() = 0; 
};

//目前只有v220的类 没有v5
class V220
	{
	public:
	void useV220() 
	{
		cout << "使用了220v的电压" << endl;
	}
};

//定义一个中间的适配器类
class Adapter :public V5
{
public:
	Adapter(V220 * v220)
	{
		this->v220 = v220;
	}
	~Adapter() {
		if (this->v220 != NULL) 
		{
			delete this->v220;
		}
	}

	virtual void useV5() 
	{
		v220->useV220(); //调用需要另外的方法
	}

private:
	V220 *v220;
};

class iPhone
{
public:
	iPhone(V5 *v5)
	{
		this->v5 = v5;
	}
	~iPhone()
	{
		if (this->v5 != NULL) {
			delete this->v5;
		}
	}

	//充电的方法
	void charge()
	{
		cout << "iphone手机进行了充电" << endl;
		v5->useV5();
	}
private:
	V5*v5; 
};

int main(void)
{
	iPhone *phone = new iPhone(new Adapter(new V220));
	phone->charge();

	return 0;
}


chunli@linux:~$ g++ main.cpp  && ./a.out 
iphone手机进行了充电
使用了220v的电压
chunli@linux:~$


适配器模式中的角色和职责 

wKiom1g9VCmijGmIAAEt9o9juAY035.png

  Target(目标抽象类): 目标抽象类定义客户所需接口,可以是一个抽

象类或接口,也可以是具体类。 

          Adapter(适配器类):适配器可以调用另一个接口,作为一个转换

器,对Adaptee和Target进行适配,适配器类是适配器模式的核心,在对象适

配器中,它通过继承Target并关联一个Adaptee对象使二者产生联系。 

         Adaptee(适配者类):适配者即被适配的角色,它定义了一个已经存在

的接口,这个接口需要适配,适配者类一般是一个具体类,包含了客户希望使

用的业务方法,在某些情况下可能没有适配者类的源代码。 

       根据对象适配器模式结构图,在对象适配器中,客户端需要调用request(

方法,而适配者类Adaptee没有该方法,但是它所提供的specificRequest()方

法却是客户端所需要的。为了使客户端能够使用适配者类,需要提供一个包装

类Adapter,即适配器类。这个包装类包装了一个适配者的实例,从而将客户

端与适配者衔接起来,在适配器的request()方法中调用适配者的

specificRequest()方法。因为适配器类与适配者类是关联关系(也可称之为委

派关系),所以这种适配器模式称为对象适配器模式。 


4.4.3 适配器模式优缺点 


优点: 

        (1) 将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者

类,无须修改原有结构。 

        (2) 增加了类的透明性和复用性, 将具体的业务实现过程封装在适配者类

中,对于客户端类而言是透明的,而且提高了适配者的复用性,同一个适配者

类可以在多个不同的系统中复用。 

        (3) 灵活性和扩展性都非常好 ,可以很方便地更换适配器,也可以在不修改

原有代码的基础上增加新的适配器类,完全符合“开闭原则”。 

  

缺点: 

      适配器中置换适配者类的某些方法比较麻烦。  




适应场景

     (1) 系统需要使用一些现有的类,而这些类的接口(如方法名)不符合系

统的需要,甚至没有这些类的源代码。 

       (2) 想创建一个可以重复使用的类,用于与一些彼此之间没有太大关联的

一些类,包括一些可能在将来引进的类一起工作。