初学设计模式之代理(Proxy)模式
1、代理模式(Proxy)的定义与概念
代理(Proxy)模式,原定义是为其他对象提供一种代理,以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中转站的作用。既然是中转站,就说明最终还是要对目标对象进行访问,只是代理对象为目标对象提供了关卡,对想要访问的对象进行检查或者处理。这样的话,目标对象专门处理自己的任务就好,代理对象帮其处理其他任务,直到非得调用目标对象才可以的时候,代理类才去调用目标对象,否则自己能处理的事物就自己处理。就相当于给目标对象聘了一个助理。其他对象想要访问目标对象,都要经过这个助理,如果这个助理能够处理就直接处理了,如果处理不了再通过助理去通知目标对象。
2、优点、缺点
优点:
1,通过上面的定义也能够发现,代理对象在客户端和目标对象之间相当于中介,因此其在一定程度上降低了耦合,更加符合迪米特法则。
2,因为是代理起到了中介的作用,自然可以对访问源起到过滤的作用,因此可以保护目标对象。
3,代理对象能处理就处理了,处理不了才去调用目标对象,帮目标对象进行减负,起到了增强目标对象的作用
4,各司其职,很符合单一职业原则。方便理解测试,和维护。
5,目标对象可能发生变化,但是只要其实现了接口,和代理对接的外部程序就不用修改,实现了高扩展性。
缺点:
1,类的数目增加
2,因为要经过代理,因此速度变慢
3,系统的复杂度变高
3、代码例子与分析
打印机本机和打印机代理的例子,打印机代理可以完成名字设置和显示,在需要打印的时候,代理需要向打印机本机进行请求
程序:
1 #include"iostream" 2 #include"string" 3 using namespace std; 4 5 class AbstractPrinter 6 { 7 public: 8 void setName(string name){}; 9 string getName(){}; 10 void print(string word){}; 11 }; 12 13 //打印机本机 14 class Printer:public AbstractPrinter 15 { 16 public: 17 Printer(string m_name) 18 { 19 name=m_name; 20 cout<<"打印机启动"<<endl; 21 }; 22 Printer() 23 {}; 24 private: 25 string name; 26 public: 27 void setName(string m_name) 28 { 29 name=m_name; 30 } 31 string getName() 32 { 33 return name; 34 } 35 void Print(string word) 36 { 37 cout<<"打印机"<<name<<"正在打印"<<endl; 38 cout<<"打印内容: "<<word<<endl; 39 cout<<"打印完成"<<endl; 40 } 41 }; 42 43 //打印机服务器 44 class PrinterProxy:public AbstractPrinter 45 { 46 private: 47 string name; 48 Printer m_printer; 49 public: 50 PrinterProxy() 51 { 52 m_printer=*(new Printer()); 53 }; 54 void setName(string m_name) 55 { 56 name=m_name; 57 } 58 string getName() 59 { 60 return name; 61 } 62 void Print(string word) 63 { 64 check(); 65 m_printer.Print(word); 66 } 67 void check() 68 { 69 m_printer=*(new Printer(name)); 70 } 71 }; 72 73 //客户端 74 int main() 75 { 76 PrinterProxy m_printerProxy; 77 m_printerProxy.setName("1号打印机"); 78 cout<<"打印代理的名字为:"<< 79 m_printerProxy.getName()<<endl; 80 cout<<"通知打印服务器"<<endl; 81 m_printerProxy.Print("打印内容"); 82 83 getchar(); 84 return 0; 85 }
运行结果
4、类图总结:
抽象主题角色:真实主题和代理主题的共同接口
真实主题角色:代理类所代表的真实目标类
代理主题角色:包含真实主题角色对象,代理角色一般在传递请求的过程中执行一些操作
5、适用场景与典型应用
适用场景:
想要为访问某个类对象提供缓存和日志服务,但是又不想打开已经封装好的目标类,可以为目标类设置一个代理类
典型应用
虚拟代理,远程代理,访问控制代理
6、关键点记忆
代理模式的关键点就是为目标对象提供一个代理,代理除了访问目标对象以外,帮其把关或者提供增值服务