设计模式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:~$
看图:
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:~$
看图
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:~$
适配器模式中的角色和职责
Target(目标抽象类): 目标抽象类定义客户所需接口,可以是一个抽
象类或接口,也可以是具体类。
Adapter(适配器类):适配器可以调用另一个接口,作为一个转换
器,对Adaptee和Target进行适配,适配器类是适配器模式的核心,在对象适
配器中,它通过继承Target并关联一个Adaptee对象使二者产生联系。
Adaptee(适配者类):适配者即被适配的角色,它定义了一个已经存在
的接口,这个接口需要适配,适配者类一般是一个具体类,包含了客户希望使
用的业务方法,在某些情况下可能没有适配者类的源代码。
根据对象适配器模式结构图,在对象适配器中,客户端需要调用request(
方法,而适配者类Adaptee没有该方法,但是它所提供的specificRequest()方
法却是客户端所需要的。为了使客户端能够使用适配者类,需要提供一个包装
类Adapter,即适配器类。这个包装类包装了一个适配者的实例,从而将客户
端与适配者衔接起来,在适配器的request()方法中调用适配者的
specificRequest()方法。因为适配器类与适配者类是关联关系(也可称之为委
派关系),所以这种适配器模式称为对象适配器模式。
4.4.3 适配器模式优缺点
优点:
(1) 将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者
类,无须修改原有结构。
(2) 增加了类的透明性和复用性, 将具体的业务实现过程封装在适配者类
中,对于客户端类而言是透明的,而且提高了适配者的复用性,同一个适配者
类可以在多个不同的系统中复用。
(3) 灵活性和扩展性都非常好 ,可以很方便地更换适配器,也可以在不修改
原有代码的基础上增加新的适配器类,完全符合“开闭原则”。
缺点:
适配器中置换适配者类的某些方法比较麻烦。
适应场景
(1) 系统需要使用一些现有的类,而这些类的接口(如方法名)不符合系
统的需要,甚至没有这些类的源代码。
(2) 想创建一个可以重复使用的类,用于与一些彼此之间没有太大关联的
一些类,包括一些可能在将来引进的类一起工作。
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。