代理模式的定义:
Provide a surrogate or placeholder for another object to control access to it.(为其他对象提供一种代理以控制对这个对象的访问。)
代理模式通用类图
代理模式代码展示与分析
抽象主题类
package proxypattern;
public interface Subject {
//定义一个该接口的功能方法
public void request();
}
具体主题类
package proxypattern;
public class RealSubject implements Subject {
@Override
public void request() {
// TODO Auto-generated method stub
System.out.println("我是具体主题角色,也叫被委托或被代理对象");
}
}
代理类
package proxypattern;
public class Proxy implements Subject {
private Subject subject = null;
//代理类的无参构造方法
public Proxy() {
//需要创建具体角色(或被代理角色)
subject = new RealSubject();
}
//代理类的有参构造方法,把代理对象传进来,一般采用这种方法
public Proxy(Subject subject) {
this.subject = subject;
}
@Override
public void request() {
// 正常情况下代理类只实现被代理的具体方法this.subject.request()就可以了
// 除了实现抽象主题所有的方法外 代理类一般也会给被代理类添加一些额外的功能
// 在真实主题角色处理完毕前后做预处理和善后处理
this.before();
this.subject.request();
this.after();
}
private void before() {
System.out.println("代理类预处理");
}
private void after() {
System.out.println("代理类善后处理");
}
}
测试类
package proxypattern;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
Subject sub = new RealSubject();
Subject proxy = new Proxy(sub);
proxy.request();
}
}
测试结果:
代理类预处理
我是具体主题角色,也叫被委托或被代理对象
代理类善后处理
代理模式分析
- 职责清晰
真实角色实现他实际的业务逻辑不用关心其他非本职的事情,其他的由后期的代理完成。 高扩展性
具体角色随时都会变化,只要它实现了接口,代理类完全可以在不做任何修改的情况下使用。使用场景:只要是要完成核心事情,减轻负担,都可以,其他的复杂中间过程交给代理完成,最经典的场景是springAOP。
代理模式的扩展
- 普通代理
- 强制代理
- 代理的个性化
动态代理
普通代理是我们必须知道代理的存在,即知道存在代理类这个类。普通代理的要求就是客户端只能访问代理角色,而不能访问真是角色。
强制代理是调用者直接调用真是角色,不用关心代理存在,其代理的产生有真实角色决定。
普通代理模式
普通代理模式在通用类图上加以修改如下图
只需要修改下具体角色类和代理类即可,测试类直接使用代理测试。
修改后的代码如下
具体角色类:
package proxypattern;
public class RealSubject implements Subject {
public RealSubject(Subject _subject) throws Exception {
if(_subject == null) {
throw new Exception("不能创建真实的角色");
}
}
@Override
public void request() {
// TODO Auto-generated method stub
System.out.println("我是具体主题角色,也叫被委托或被代理对象");
}
}
代理类:
package proxypattern;
public class Proxy implements Subject {
private Subject subject = null;
//代理类的无参构造方法
public Proxy() {
try {
subject = new RealSubject(this);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void request() {
// 正常情况下代理类只实现被代理的具体方法this.subject.request()就可以了
// 除了实现抽象主题所有的方法外 代理类一般也会给被代理类添加一些额外的功能
// 在真实主题角色处理完毕前后做预处理和善后处理
this.before();
this.subject.request();
this.after();
}
private void before() {
System.out.println("代理类预处理");
}
private void after() {
System.out.println("代理类善后处理");
}
}
测试类:
package proxypattern;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
Subject proxy = new Proxy();
proxy.request();
}
}
测试结果
代理类预处理
我是具体主题角色,也叫被委托或被代理对象
代理类善后处理
结果和通用代码完全一致
强制代理模式
一般的思维都是通过代理找到真实角色,强制代理的思维是通过真实角色找到代理,否则不能访问。
修改下具体角色类和代理类,接口添加一行代码就可实现
修改后的代码如下
抽象主题接口
package proxypattern;
public interface Subject {
//定义一个该接口的功能方法
public void request();
public Subject getProxy();
}
具体角色类
package proxypattern;
public class RealSubject implements Subject {
private Subject proxy = null;
public RealSubject() {}
@Override
public Subject getProxy() {
this.proxy = new Proxy(this);
return this.proxy;
}
@Override
public void request() {
// TODO Auto-generated method stub
if(this.isProxy()) {
System.out.println("我是具体主题角色,也叫被委托或被代理对象");
} else {
System.out.println("请使用指定代理访问");
}
}
private boolean isProxy() {
if(this.proxy == null) {
return false;
} else {
return true;
}
}
}
代理类
package proxypattern;
public class Proxy implements Subject {
private Subject subject = null;
//代理类的无参构造方法
public Proxy(Subject _subject) {
this.subject = _subject;
}
@Override
public void request() {
// 正常情况下代理类只实现被代理的具体方法this.subject.request()就可以了
// 除了实现抽象主题所有的方法外 代理类一般也会给被代理类添加一些额外的功能
// 在真实主题角色处理完毕前后做预处理和善后处理
this.before();
this.subject.request();
this.after();
}
private void before() {
System.out.println("代理类预处理");
}
private void after() {
System.out.println("代理类善后处理");
}
@Override
public Subject getProxy() {
// TODO Auto-generated method stub
return this;
}
}
测试类一 (对象直接访问)
package proxypattern;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
Subject sub = new RealSubject();
sub.request();
}
}
输出结果
请使用指定代理访问
测试二 (通用测试类,将具体主题对象交给代理)
package proxypattern;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
Subject sub = new RealSubject();
Subject proxy = new Proxy(sub);
proxy.request();
}
}
测试结果
代理类预处理
请使用指定代理访问
代理类善后处理
测试三 (通过对象获取代理,再通过代理执行内容)
package proxypattern;
public class Test {
public static void main(String[] args) {
Subject sub = new RealSubject();
Subject proxy = sub.getProxy();
proxy.request();
}
}
测试结果
代理类预处理
我是具体主题角色,也叫被委托或被代理对象
代理类善后处理
与通用类图结果一致
代理的个性化
通过接口对不同任务进行整合,在目标对象的方法的基础上作增强,这种增强的本质通常就是对目标的对象方法进行拦截和过滤。
代理类不仅仅是可以有自己的运算方法,通常情况下代理的职责并不一定单一,它可以组合其他的真实角色,也可以实现自己的职责。代理类可以为真实角色预处理消息、过滤消息、消息转发、事后处理消息等等。
个性化类图如下
添加接口IProxy
package proxypattern;
public interface IProxy {
public void count();
}
代理类在通用代码上做如下修改
package proxypattern;
public class Proxy implements Subject,IProxy {
private Subject subject = null;
//代理类的无参构造方法
public Proxy() {
//需要创建具体角色(或被代理角色)
subject = new RealSubject();
}
//代理类的有参构造方法,把代理对象传进来,一般采用这种方法
public Proxy(Subject subject) {
this.subject = subject;
}
@Override
public void request() {
// 正常情况下代理类只实现被代理的具体方法this.subject.request()就可以了
// 除了实现抽象主题所有的方法外 代理类一般也会给被代理类添加一些额外的功能
// 在真实主题角色处理完毕前后做预处理和善后处理
this.before();
this.subject.request();
this.after();
}
private void before() {
System.out.println("代理类预处理");
}
private void after() {
System.out.println("代理类善后处理");
}
@Override
public void count() {
// TODO Auto-generated method stub
System.out.println("其他接口计算功能");
}
}
测试类在通用代码上做如下修改
package proxypattern;
public class Test {
public static void main(String[] args) {
Subject sub = new RealSubject();
Proxy proxy = new Proxy(sub);
proxy.request();
proxy.count();
}
}
输出结果为
代理类预处理
我是具体主题角色,也叫被委托或被代理对象
代理类善后处理
其他接口计算功能
动态代理模式太重要下一章节单独展示。