代理模式
简介
代理模式定义:为被代理对象提供代理以控制该对象的访问权限。例如我们想找明星出演商业活动的时候是不可以直接联系本人的,是需要联系经纪人。
代理模式通用类图
入门案例一
例如我想找颖宝去演出某部电视剧,颖宝平时的工作很忙,如果什么事情都要自己处理的话,就会显得很劳累。所以才有明星经纪人的出现,那么经纪人其实就是颖宝的代理人的。代理颖宝处理一部分事情,你要找颖宝就必须通过经纪人。
那么问题就来了,经纪人总要知道颖宝会那些技能吧!不能随便就接了一些活动,颖宝不会的话那么不就相当于捣乱了吗?还没有分担颖宝的压力。对应到Java代码中,就是经纪人(代理人)和颖宝(被代理人)需要有公共的接口。
代码
package com.rabbit.pattern.proxy;
/**
* 代理人和被代理人共识技能类
* Created by vip on 2018/3/1.
*/
public interface Skill {
/**
* 唱歌
* @param name
*/
void sing(String name);
/**
* 演出
* @param name
*/
void perform(String name);
/**
* 综艺节目
* @param name
*/
void variety(String name);
}
package com.rabbit.pattern.proxy;
/**
* 颖宝
* Created by vip on 2018/3/1.
*/
public class YingBao implements Skill {
@Override
public void sing(String name) {
System.out.println("颖宝唱了一首[" + name + "]");
}
@Override
public void perform(String name) {
System.out.println("颖宝出演了[" + name + "]");
}
@Override
public void variety(String name) {
System.out.println("颖宝上[" + name + "]综艺节目");
}
}
package com.rabbit.pattern.proxy;
/**
* 颖宝经纪人
* Created by vip on 2018/3/1.
*/
public class YingBaoProxy implements Skill {
//保存被代理人的实例
private Skill yb;
public YingBaoProxy(Skill skill) {
this.yb = skill;
}
//代理人实际是让颖宝去做事情
@Override
public void sing(String name) {
yb.sing(name);
}
@Override
public void perform(String name) {
yb.perform(name);
}
@Override
public void variety(String name) {
yb.variety(name);
}
}
package com.rabbit.pattern.proxy;
/**
* Created by vip on 2018/3/1.
*/
public class Demo {
public static void main(String[] args) {
YingBaoProxy ybp = new YingBaoProxy(new YingBao());
ybp.sing("北京北京");
ybp.perform("陆贞传奇");
ybp.variety("天天向上");
}
}
代理模式优缺点
优点
职责清晰
被代理对象只负责自己实际的业务逻辑,不关心其他非本身的职责。并将其他事务可以通过代理类处理。
高扩展性
无论被代理对象如何改变,只要代理类和被代理类都实现了统一接口,都不同修改代理类,而且即使扩展了新的被代理类,代理类也可以使用,只要创建代理类的时候传入对应的被代理类对象。
智能化
这主要体现在动态代理中,下面会讲解动态代理。如果有兴趣了解Spring的AOP,其实就是使用了动态代理。
缺点
如果不合理的使用代理模式,可能会导致请求处理速度变慢,降低并发量。实现代理模式需要额外的工作,这会导致资源的消耗,如果复杂的代理模式可能会降低系统性能。
代理方式
在入门案例一中代理类通过构造函数让调用者指定要代理的对象,这其实是一种比较广泛的调用方式,因为这个代理类可以代理任何实现了Skill的类。
指定代理类
还是使用入门案例一中的例子,但是被代理类指定代理类,其他代理类如果强行调用将不可以执行。思路:先通过被代理类获取指定的代理对象来访问。
package com.rabbit.pattern.proxy;
/**
* 代理人和被代理人共识技能类
* Created by vip on 2018/3/1.
*/
public interface Skill {
/**
* 唱歌
* @param name
*/
void sing(String name);
/**
* 演出
* @param name
*/
void perform(String name);
/**
* 综艺节目
* @param name
*/
void variety(String name);
}
package com.rabbit.pattern.proxy;
/**
* 颖宝
* Created by vip on 2018/3/1.
*/
public class YingBao implements Skill {
private YingBaoProxy ybp;//颖宝指定的代理人
//获取指定的代理人对象
public Skill getProxt() {
ybp = new YingBaoProxy(this);
return ybp;
}
@Override
public void sing(String name) {
if (ybp == null) {
System.out.println("请使用指定的代理类");
} else {
System.out.println("颖宝唱了一首[" + name + "]");
}
}
@Override
public void perform(String name) {
if (ybp == null) {
System.out.println("请使用指定的代理类");
} else {
System.out.println("颖宝出演了[" + name + "]");
}
}
@Override
public void variety(String name) {
if (ybp == null) {
System.out.println("请使用指定的代理类");
} else {
System.out.println("颖宝上[" + name + "]综艺节目");
}
}
}
package com.rabbit.pattern.proxy;
/**
* 颖宝经纪人
* Created by vip on 2018/3/1.
*/
public class YingBaoProxy implements Skill {
//保存被代理人的实例
private Skill yb;
public YingBaoProxy(Skill skill) {
this.yb = skill;
}
//代理人实际是让颖宝去做事情
@Override
public void sing(String name) {
yb.sing(name);
}
@Override
public void perform(String name) {
yb.perform(name);
}
@Override
public void variety(String name) {
yb.variety(name);
}
}
package com.rabbit.pattern.proxy;
/**
* Created by vip on 2018/3/1.
*/
public class Demo {
public static void main(String[] args) {
Skill ybp = new YingBao().getProxt();
ybp.sing("北京北京");
ybp.perform("陆贞传奇");
ybp.variety("天天向上");
}
}
动态代理
介绍动态代理之前我们先了解需要使用到的2个类。
1)Interface InvocationHandler:该接口中仅定义了一个方法Object:invoke(Object obj,Method method,Object[] args)。在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,args为该方法的参数数组。这个抽象方法在代理类中动态实现。
2)Proxy:该类即为动态代理类,作用类似于上例中的ProxySubject,其中主要包含以下内容:
Protected Proxy(InvocationHandler h):构造函数,估计用于给内部的h赋值。
Static Class getProxyClass (ClassLoader loader,Class[]interfaces):获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。
Static Object newProxyInstance(ClassLoaderloader,Class[] interfaces,InvocationHandler h):返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在Subject接口中声明过的方法)。
package com.rabbit.pattern.proxy;
/**
* 代理人和被代理人共识技能类
* Created by vip on 2018/3/1.
*/
public interface Skill {
/**
* 唱歌
* @param name
*/
void sing(String name);
/**
* 演出
* @param name
*/
void perform(String name);
/**
* 综艺节目
* @param name
*/
void variety(String name);
}
package com.rabbit.pattern.proxy;
/**
* 颖宝
* Created by vip on 2018/3/1.
*/
public class YingBao implements Skill {
@Override
public void sing(String name) {
System.out.println("颖宝唱了一首[" + name + "]");
}
@Override
public void perform(String name) {
System.out.println("颖宝出演了[" + name + "]");
}
@Override
public void variety(String name) {
System.out.println("颖宝上[" + name + "]综艺节目");
}
}
package com.rabbit.pattern.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 调度处理类,动态代理对象创建时候使用
* Created by vip on 2018/3/1.
*/
public class MyInvocationHandler implements InvocationHandler {
private Object obj;//被代理类实例
public MyInvocationHandler(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理对象要处理的公共逻辑可以统一写到这里");
if (method.getName().equalsIgnoreCase("sing")) {
System.out.println("我已经不在接唱歌的业务了,不好意思");
return null;
}
Object invoke = method.invoke(obj, args);
return invoke;
}
}
package com.rabbit.pattern.proxy;
import java.lang.reflect.Proxy;
/**
* Created by vip on 2018/3/1.
*/
public class Demo {
public static void main(String[] args) throws Exception {
Skill yb = new YingBao();
//创建调度对象
MyInvocationHandler mih = new MyInvocationHandler(yb);
//动态代理的方式创建对象
Skill s = (Skill)Proxy.newProxyInstance(yb.getClass().getClassLoader(), new Class[]{Skill.class}, mih);
s.sing("小幸运");
s.perform("陆贞传奇");
s.variety("天天向上");
}
}
动态代理的好处
可能会觉得动态代理在使用的过程中需要额外的代码,例如“创建调度对象”和“动态代理的方式创建对象”这些代码,但是这都是可以继续封装的。动态代理的好处就是对象只有在需要使用的时候才动态代理,这里少了一个YingBaoSKill类,而且对于扩展了SKill类的子类,不需要额外的去创建一个新的类。
装饰者模式和代理模式
装饰者模式:http://blog.csdn.net/sinat_32366329/article/details/79392905
装饰者
1) 装饰者模式主要是为了增强被装饰者类的功能,可以说是继承的一种替代方案。
2) 隐藏了被装饰者类的具体实现,对于调用方来说只知道装饰者类。
代理
1) 代理模式主要是为了增强被代理类的权限控制。
2) 隐藏了被代理类具体实现,对于调用方来说只知道代理类。
装饰者模式和代理模式的实现机制都很像,但是为什么一样的机制要区分出2种设计模式呢?可以说是为了单一职责原则不被破坏。因为2个模式的具体职责不一样,如果都叫装饰者模式或者都叫代理模式那么开发人员就区分不出来具体的作用。对于区分出2种职责可以说为了更加容易理解吧!