博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
设计模式之代理模式(一)
阅读量:6156 次
发布时间:2019-06-21

本文共 10039 字,大约阅读时间需要 33 分钟。

一、什么是代理模式

定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。

组成:
抽象角色(主题):通过接口或抽象类声明真实角色实现的业务方法。
代理角色(代理对象):实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。
真实角色(被代理对象):实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。

二、为什么要使用代理模式

意图:为其他对象提供一种代理以控制对这个对象的访问。

主要解决:在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。

应用实例:1、Windows 里面的快捷方式。2、买火车票不一定在火车站买,也可以去代售点。 3、spring aop。

优点: 1、职责清晰。

    被代理对象只负责自己实际的业务逻辑,不关心其他非本身的职责。并将其他事务可以通过代理类处理。

       2、高扩展性。

    无论被代理对象如何改变,只要代理类和被代理类都实现了统一接口,都不同修改代理类,而且即使扩展了新的被代理类,代理类也可以使用,只要创建代理类的时候传入对应的被代理类对象。

    3、智能化。

    这主要体现在动态代理中,下面会讲解动态代理。如果有兴趣了解Spring的AOP,其实就是使用了动态代理。

缺点: 1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。

       2、实现代理模式需要额外的工作,有些代理模式的实现非常复杂。

注意事项: 1、和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。

         2、和装饰器模式的区别:装饰器模式为了增强功能,而代理模式是为了加以控制。

三、如何用代理模式

  我们举个示例,比如在娱乐圈,客户与艺人进行商业合作,一般都不是与艺人直接联系,签订时间、地点、薪酬等合同,而是

找艺人的经纪人商讨,那么这里商艺活动就是抽象对象(主题),艺人就被代理对象,经纪人就是代理对象。

代码示例:

首先我们来看一个最基本的代理模式:

package com.pattern.proxy1;/** *  抽象接口 演艺 */public interface Performance {    public void Sing(String name, String address, String date);//谁在哪个时间哪个地点唱歌    public void dance(String name, String address, String date); //谁在哪个时间哪个地点跳舞    public void perform(String name, String address, String date);//谁在哪个时间哪个地点表演}
抽象对象(主题接口)
package com.pattern.proxy1;/** *  被代理对象 艺人 */public class Artist implements Performance {    @Override    public void Sing(String name, String address, String date) {        System.out.println(date+"    "+name  +"在"+address +"rap了一首xX");    }    @Override    public void dance(String name, String address, String date) {        System.out.println( date+"    "+name  +"在"+address +"跳了一个芭蕾");    }    @Override    public void perform(String name, String address, String date) {        System.out.println(date+"    "+name  +"在"+address +"表演了打篮球");    }}
被代理对象
package com.pattern.proxy1;/** * 代理对象 经纪人 * Created by wanbf on 2019/5/26. */public class Agent  implements Performance {    //保存被代理人的实例    private Performance performance;    public Agent(Performance performance){        this.performance = performance;    }    @Override    public void Sing(String name, String address, String date) {        System.out.println("经济人和客户确定时间地点等一系列细节后...");        performance.Sing(name,address,date);//这里经纪人是不会唱歌的,执行艺人的唱歌 下同    }    @Override    public void dance(String name, String address, String date) {        System.out.println("经济人和客户确定时间地点等一系列细节后...");        performance.dance(name,address,date);    }    @Override    public void perform(String name, String address, String date) {        System.out.println("经济人和客户确定时间地点等一系列细节后...");        performance.perform(name,address,date);    }}
代理对象
package com.pattern.proxy1;import java.text.DateFormat;import java.util.Date;/** * Created by wanbf on 2019/5/26.   这里是最基本代理模式示例 */public class Main {    public static void consumer(Performance performance){        performance.Sing("CXK","韩国", DateFormat.getDateInstance().format(new Date()));        performance.dance("CXK","韩国",DateFormat.getDateInstance().format(new Date()));        performance.perform("CXK","韩国",DateFormat.getDateInstance().format(new Date()));    }    public static void main(String[] args){        consumer(new Artist());        System.out.println("----------------");        consumer(new Agent(new Artist()));    }}
测试
输出:2019-5-27    CXK在韩国rap了一首xX2019-5-27    CXK在韩国跳了一个芭蕾2019-5-27    CXK在韩国表演了打篮球----------------经济人和客户确定时间地点等一系列细节后...2019-5-27    CXK在韩国rap了一首xX经济人和客户确定时间地点等一系列细节后...2019-5-27    CXK在韩国跳了一个芭蕾经济人和客户确定时间地点等一系列细节后...2019-5-27    CXK在韩国表演了打篮球
输出

从示例中我们可以看出 客户直接调用 被代理人对象 和 代理人对象的区别在于一些额外的操作从 “实际”对象中 分离到不同的地方,特别是当你能够很容易的做出修改,从没有额外操作转为使用这些操作。

那么在示例中客户(抽象对象、主题接口)想要的只是艺人的表演,而艺人(被代理对象)只管表演,那么其中一些比如时间地点细节操作 交给经纪人(代理对象) 去完成,然后在调用艺人去完成表演。

在实际项目中,额外的操作多数是日志记录操作。

 再来看一个普通代理模式:

package com.pattern.proxy2;/** *  抽象接口 演艺 */public interface Performance {    public void Sing(String name, String address, String date);//谁在哪个时间哪个地点唱歌    public void dance(String name, String address, String date); //谁在哪个时间哪个地点跳舞    public void perform(String name, String address, String date);//谁在哪个时间哪个地点表演}
抽象对象(主题接口)
package com.pattern.proxy2;/** *  被代理对象 艺人 */public class Artist implements Performance {    //通过构造方法将代理传进来    public Artist( Performance performance) {        if (performance == null){            System.out.println("不是通过代理人进来的");        }    }    @Override    public void Sing(String name, String address, String date) {        System.out.println(date+"    "+name  +"在"+address +"rap了一首xX");    }    @Override    public void dance(String name, String address, String date) {        System.out.println( date+"    "+name  +"在"+address +"跳了一个芭蕾");    }    @Override    public void perform(String name, String address, String date) {        System.out.println(date+"    "+name  +"在"+address +"表演了打篮球");    }}
被代理对象
package com.pattern.proxy2;/** * 代理对象 经纪人 * Created by wanbf on 2019/5/26. */public class Agent  implements Performance {    //保存被代理人的实例    private Performance performance;    public Agent(){        //通过构造方法创建 Artist,将自己传递出去        this.performance = new Artist(this);    }    @Override    public void Sing(String name, String address, String date) {        System.out.println("经济人和客户确定时间地点等一系列细节后...");        performance.Sing(name,address,date);//这里经纪人是不会唱歌的,执行艺人的唱歌 下同    }    @Override    public void dance(String name, String address, String date) {        System.out.println("经济人和客户确定时间地点等一系列细节后...");        performance.dance(name,address,date);    }    @Override    public void perform(String name, String address, String date) {        System.out.println("经济人和客户确定时间地点等一系列细节后...");        performance.perform(name,address,date);    }}
代理对象
package com.pattern.proxy2;import java.text.DateFormat;import java.util.Date;/** * Created by wanbf on 2019/5/26.   这里是普通代理模式示例 */public class Main {    public static void consumer(Performance performance){        performance.Sing("CXK","韩国", DateFormat.getDateInstance().format(new Date()));        performance.dance("CXK","韩国",DateFormat.getDateInstance().format(new Date()));        performance.perform("CXK","韩国",DateFormat.getDateInstance().format(new Date()));    }    public static void main(String[] args){        Performance performance = new Agent();        consumer(performance);        System.out.println("----------------");      //  consumer(new Agent(new Artist()));    }}
测试
输出:经济人和客户确定时间地点等一系列细节后...2019-5-27    CXK在韩国rap了一首xX经济人和客户确定时间地点等一系列细节后...2019-5-27    CXK在韩国跳了一个芭蕾经济人和客户确定时间地点等一系列细节后...2019-5-27    CXK在韩国表演了打篮球----------------
输出

从测试代码可以看出,我们调用 是用知道被代理对象 真实角色是谁的,只有代理对象知道,那么屏蔽了真实角色的变更 对整个模块的影响。

 在看一个强制代理模式

package com.pattern.proxy;/** *  抽象接口 演艺 */public interface Performance {    public void Sing(String name , String address, String date);//谁在哪个时间哪个地点唱歌    public void dance(String name , String address, String date); //谁在哪个时间哪个地点跳舞    public void perform(String name , String address, String date);//谁在哪个时间哪个地点表演}
抽象对象(主题)
package com.pattern.proxy;/** *  被代理对象 艺人 */public class Artist implements Performance{    private Agent agent;// 获取指定代理人对象    //获取指定的代理人对象    public Performance getAgent(){        agent = new Agent(this);        return agent;    }    @Override    public void Sing(String name, String address, String date) {        if (agent == null){            System.out.println("请使用指定的代理类");        }else        System.out.println(date+"    "+name  +"在"+address +"rap了一首xX");    }    @Override    public void dance(String name, String address, String date) {        if (agent == null){            System.out.println("请使用指定的代理类");        }else            System.out.println( date+"    "+name  +"在"+address +"跳了一个芭蕾");    }    @Override    public void perform(String name, String address, String date) {        if (agent == null){            System.out.println("请使用指定的代理类");        }else            System.out.println(date+"    "+name  +"在"+address +"表演了打篮球");    }}
被代理对象
package com.pattern.proxy;/** * 代理对象 经纪人 * Created by wanbf on 2019/5/26. */public class Agent  implements Performance{    //保存被代理人的实例    private Performance performance;    public Agent(Performance performance){        this.performance = performance;    }    @Override    public void Sing(String name, String address, String date) {        performance.Sing(name,address,date);//这里经纪人是不会唱歌的,执行艺人的唱歌 下同    }    @Override    public void dance(String name, String address, String date) {        performance.dance(name,address,date);    }    @Override    public void perform(String name, String address, String date) {        performance.perform(name,address,date);    }}
代理对象
public static void main(String[] args){        Performance performance = new Artist().getAgent();        performance.Sing("CXK","韩国", DateFormat.getDateInstance().format(new Date()));        performance.dance("CXK","韩国",DateFormat.getDateInstance().format(new Date()));        performance.perform("CXK","韩国",DateFormat.getDateInstance().format(new Date()));    }输出:2019-5-26    CXK在韩国rap了一首xX2019-5-26    CXK在韩国跳了一个芭蕾2019-5-26    CXK在韩国表演了打篮球
测试

上面我们是走指定的代理对象 执行方法;

那么我们不通过代理方法来执行呢,

//不通过代理还执行Performance performance = new Artist();performance.Sing("CXK","韩国", DateFormat.getDateInstance().format(new Date()));performance.dance("CXK","韩国",DateFormat.getDateInstance().format(new Date()));performance.perform("CXK","韩国",DateFormat.getDateInstance().format(new Date()));输出:请使用指定的代理类请使用指定的代理类请使用指定的代理类
不走代理方法

很显然,不用代理方法是不能执行成功的

不是指定代理方法呢,

//不是指定的代理方法Performance performance = new Agent(new Artist());performance.Sing("CXK","韩国", DateFormat.getDateInstance().format(new Date()));performance.dance("CXK","韩国",DateFormat.getDateInstance().format(new Date()));performance.perform("CXK","韩国",DateFormat.getDateInstance().format(new Date()));输出:请使用指定的代理类请使用指定的代理类请使用指定的代理类
不是指定的代理方法

显然不是指定的代理方法也是执行不了的

 这个示例是强制代理模式,概念就是要从真是角色那里查找到代理角色,不允许直接访问真实角色。

上层模块只需要调用Agent()获取代理来访问真实角色的所有方法,它根本就不需要产生一个代理角色,代理的管理已经由真实角色自己来完成。

后续讲解一个 虚拟代理模式 和动态代理模式。

转载于:https://www.cnblogs.com/justBobo/p/10927408.html

你可能感兴趣的文章
Qt Style Sheet实践(四):行文本编辑框QLineEdit及自动补全
查看>>
[物理学与PDEs]第3章习题1 只有一个非零分量的磁场
查看>>
深入浅出NodeJS——数据通信,NET模块运行机制
查看>>
onInterceptTouchEvent和onTouchEvent调用时序
查看>>
android防止内存溢出浅析
查看>>
4.3.3版本之引擎bug
查看>>
SQL Server表分区详解
查看>>
使用FMDB最新v2.3版本教程
查看>>
STM32启动过程--启动文件--分析
查看>>
垂死挣扎还是涅槃重生 -- Delphi XE5 公布会归来感想
查看>>
淘宝的几个架构图
查看>>
linux后台运行程序
查看>>
Python异步IO --- 轻松管理10k+并发连接
查看>>
Oracle中drop user和drop user cascade的区别
查看>>
登记申请汇总
查看>>
Android Jni调用浅述
查看>>
CodeCombat森林关卡Python代码
查看>>
第一个应用程序HelloWorld
查看>>
(二)Spring Boot 起步入门(翻译自Spring Boot官方教程文档)1.5.9.RELEASE
查看>>
Shell基础之-正则表达式
查看>>