概念
Proxy模式又叫做代理模式,是构造型的设计模式之一,它可以为目标对象提供一种代理(Proxy)以控制对这个对象的访问。
理解代理
代理与代理元(被代理的对象)实现相同的接口,客户端必须通过代理与被代理的目标类交互,而代理一般在交互的过程中(交互前后),进行某些特别的处理。
图解
1、代理图解
2、uml类图
代理中的概念
- subject(抽象主题角色)
真实主题与代理主题的共同接口。 - RealSubject(真实主题角色)
定义了代理角色所代表的真实对象。 - Proxy(代理主题角色)
含有对真实主题角色的引用,代理角色通常在将客户端调用传递给真实主题对象之前或者之后执行某些操作,而不是单纯返回真实的对象。
Proxy这个类含义理解
1、含有对真实主题角色的引用:也就是说代理类含有被代理类的引用。
2、代理角色通常在将客户端调用传递给真实主题对象之前或者之后执行某些操作,而不是单纯返回真实的对象:也就是说在代理类中行驶被代理类的功能之前之后我们还可以做其他操作。
总结代理写法
1、创建接口(被代理类的功能抽象出来的)
2、代理类与被代理类实现同一接口(是不是想起了装饰者模式,静态代理与装饰者就是像)
3、代理类中进行功能代理,在代理这个功能前后还可以做些代理类特有的工作
一般适用静态,动态跟这差不多
代理分类:
代码实战卖书栗子
书店、出版社 。二者是代理与被代理的关系。
1、书店可以卖书,卖书同时还可以搞优惠,打折送优惠券。
2、出版社只能卖书,且委托书店代理。
接下来我们便结合unl类图以及代理的书写法。来写下动态、静态代理。
1、抽象接口:卖书
package pattern_proxy.static_proxy;
/**
* Create by SunnyDay on 2019/04/14
* 接口(功能抽象而来)
*/
public interface Subject {
void sailBook();//卖书
}
2、代理类与被代理类实现同一接口
被代理类:
package pattern_proxy.static_proxy;
/**
* Create by SunnyDay on 2019/04/14
* 被代理的类
*/
public class RealSubject implements Subject {
@Override
public void sailBook() {
System.out.println("卖书ing");
}
}
代理类:
package pattern_proxy.static_proxy;
/**
* Create by SunnyDay on 2019/04/14
* 代理类
*/
public class ProxySubject implements Subject {
private Subject subject;//传被代理类对象引用
//这里使用setter也行,不一定使用构造
public ProxySubject(Subject subject) {
this.subject = subject;
}
/**
* 代理卖书功能,自己还做点功能。
*/
@Override
public void sailBook() {
// 行驶被代理类的功能前后同时再做点其他功能
dazhe();
subject.sailBook();//行驶被代理类的功能
give();
}
/**
* 打折,代理类添加的小功能
* */
private void dazhe() {
System.out.println("卖书吗?书打折");
}
/**
* 送优惠券,代理类添加的小功能
* */
private void give() {
System.out.println("给你代金券");
}
}
3、静态代理的优缺点:
优点:业务类只需要关注业务逻辑本身,保证了业务类的重用性。这是代理的共有优点。
缺点:如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
4、静态代理与装饰者对比
相同点:
(1)都要实现与目标类相同的业务接口
(2)在俩个类中都要声明目标对象
(3)都可以在不修改目标类的前提下增强目标方法
不同点:
(1)目的不同,装饰者,简单说,就是为了增强目标对象。 静态代理的使用目的是为了保护和隐藏目标对象
(2)功能增强的实现者不同 装饰者设计模式中存在装饰者基类,其并不能实现增强,而是由具体的装饰者进行增强的,所以其存在着"装饰者链"。而静态代理中,一般不存在父子类的关系,具体的增强,就是由代理类实现的。无需其子类完成,所以不存在 链 的概念。
参考:https://blog.csdn.net/weixin_35609314/article/details/78913635
动态代理栗子(还是卖书)
学习动态代理之前我们最好了解反射、类加载相关知识。
1、反射参考:https://www.jianshu.com/p/8fdadceb5ed1
2、类加载参考:深入理解java虚拟机第七章
动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以不存在代理类的字节码文件。代理类和委托类的关系是在程序运行时确定。
java提供了相关接口:(我们实现即可)
栗子:
接口,被代理类还是用写好的。
新建代理类:
package pattern_proxy.auto_proxy;
import pattern_proxy.static_proxy.Subject;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* Create by SunnyDay on 2019/04/14
* <p>
* 动态代理类:创建类实现InvocationHandler接口
*/
public class MyHandler implements InvocationHandler {
private Subject subject;
public MyHandler(Subject subject) {
this.subject = subject;
}
/**
* @function 在代理实例上处理方法调用并返回结果。
* 在与方法关联的代理实例上调用方法时,
* 将在调用处理程序上调用此方法。(来自api文档解释)
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
dazhe();
result = method.invoke(subject);
give();
return result;
}
//
private void dazhe() {
System.out.println("卖书吗?书打折");
}
//
private void give() {
System.out.println("给你代金券");
}
}
测试代码中调用:
package pattern_proxy;
import pattern_proxy.auto_proxy.MyHandler;
import pattern_proxy.static_proxy.ProxySubject;
import pattern_proxy.static_proxy.RealSubject;
import pattern_proxy.static_proxy.Subject;
import java.lang.reflect.Proxy;
/**
* Create by SunnyDay on 2019/04/14
*/
public class Test {
public static void main(String[] args) {
// 静态
// ProxySubject proxySubject = new ProxySubject(new RealSubject());
// proxySubject.sailBook();
MyHandler myHandler = new MyHandler(new RealSubject());
//动态
Subject subjectProxy = (Subject) Proxy.newProxyInstance(RealSubject.class.getClassLoader(), RealSubject.class.getInterfaces(), myHandler);
subjectProxy.sailBook();
}
}
小结
动态代理不好理解,源码分析略以后再探讨,这里先学下设计模式书写。。。。。