创建式模式:抽象工厂/建造者/工厂方法/原型/单例
构造型模式:适配器/桥接/组合/装饰/外观/享元/代理
行为型模式:责任链/命令/解释器/迭代子/中介者/备忘录/观察者/状态/策略/模板方法/访问者
.......
.......
代理模式:使用一个新的代理类为目标类(被代理类)进访问的控制,与装饰者模式不同,代理类对象可以有多个目标类,控制的目的是为了在调用目标类方法之前或之后执行某些其他操作、或者增强或减弱目标类的某些方法中的功能,作为一个委托者起到不改变目标类的核心代码就能够实现功能的增强或新功能的添加的作用。
静态代理:当被代理类(目标类)与代理类(委托类)在程序运行之前已经存在,即运行前就确定了关系生成了字节码文件,这种由委托类和目标类形成的代理关系就是静态代理。
代理实例:(经纪人代理明星)【前提是经纪人和明星实现了相同接口】
接口:
/**
* 接口(目标类和委托类必须实现同一个接口)
*/
public interface Star {
public void action();
}
委托类:
/**
* 经纪人类(作为委托类),要和目标类实现相同的接口
* 可以代理多个实现了相同接口的目标对象(通过构造函数传入实例对象的引用,面向接口编程、多态)
*/
public class Agent implements Star{
private Star Star;
public Agent(Star star) {
Star = star;
}
private void actionBefore(){
System.out.println("委托者(当前是经纪人)在演出之前执行前置工作");
}
@Override
public void action() {
//在目标类代码执行之前,添加其他的功能或处理部分逻辑
//代理明星的演出前对第三方邀请商的签约工作
actionBefore();
//执行目标类的核心工作,真正的执行者
Star.action();
//代理明星的演出后对片酬的分发动作等等
actionAfter();
}
private void actionAfter(){
System.out.println("委托者(当前是经纪人)在演出后执行后置工作");
}
}
目标类:
public class Songer implements Star{
@Override
public void action() {
System.out.println("歌手唱歌");
}
}
public class Actor implements Star{
@Override
public void action() {
System.out.println("演员表演");
}
}
测试当前实例的测试类:
public class StaticProxyTest {
@Test
public void test(){
//创建一个歌手让经纪人代理,在歌手之前或之后进行功能的加强或处理
Songer songer = new Songer();
new Agent(songer).action();
//创建一个演员让经纪人代理,在演员出演之前或之后进行功能的加强或处理
Actor actor = new Actor();
new Agent(actor).action();
}
}
1.代理对象服务于实现了相同接口的对象,如果要代理的方法很多,势必要为每一种方法都进行代理,静态代理在程序规模稍大时就无法胜任了。
2.如果接口增加一个方法,除了所有委托类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
动态代理:(基于JDK的动态代理\Proxy方式)
动态代理它可以直接给某一个目标对象(委托对象)生成一个代理对象,而不需要代理类存在。动态代理与静态代理模式原理是一样的,只是动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以不存在代理类的字节码文件。代理类和委托类的关系是在程序运行时确定。
代理实例:(也用经纪人代理明星这个例子)【前提是经纪人和明星实现了相同接口】
接口:
/**
* 接口(目标类和委托类必须实现同一个接口)
*/
public interface Star {
public void action();
}
目标类:
public class Songer implements Star{
@Override
public void action() {
System.out.println("歌手唱歌");
}
}
委托类由JVM通过反射动态生成
{
调用处理者类:
/**
* 调用处理者(这里统一处理目标类方法的调用逻辑)
*/
public class InvocationHandlerImp implements InvocationHandler{
private Star star;
public InvocationHandlerImp(Star star) {
this.star = star;
}
/**
*
* @param proxy 当前创建出来的动态代理对象
* @param method 当前调用的方法对象
* @param args 调用的方法参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//创建一个歌手让经纪人代理,在歌手之前或之后进行功能的加强或处理
actionBefore();
//调用当前目标类对象的方法
method.invoke(star);
//代理明星的演出后对片酬的分发动作等等
actionAfter();
return null;
}
private void actionBefore(){
System.out.println("委托者(当前是经纪人)在演出之前执行前置工作");
}
private void actionAfter(){
System.out.println("委托者(当前是经纪人)在演出后执行后置工作");
}
}
结合Proxy类生成代理对象
InvocationHandlerImp invocationHandlerImp = new InvocationHandlerImp(star);
//参数一是一个类加载器
//参数二是目标类上的所有接口的字节码对象
//参数三是委托者的调用处理者对象
Star starProxy= (Star) Proxy.newProxyInstance(this.getClass().getClassLoader(), Songer.class.getInterfaces(), invocationHandlerImp);
}
测试类代码:
public class DynamicProxyTest {
@Test
public void test(){
//创建目标类对象
Star star = new Songer();
//创建委托类的调用处理者
InvocationHandlerImp invocationHandlerImp = new InvocationHandlerImp(star);
//参数一是一个类加载器
//参数二是目标类上的所有接口的字节码对象
//参数三是委托者的调用处理者对象
Star starProxy= (Star) Proxy.newProxyInstance(this.getClass().getClassLoader(), Songer.class.getInterfaces(), invocationHandlerImp);
//调用代理对象的方法(在执行目标类方法之前执行其他业务操作,可以增强了当前目标类的方法,但是实际上核心工作还是目标类完成)
//代理对象每调用一个方法,都会执行一次调用处理者中的invoke方法,可以通过判断方法名去筛选要处理的方法
starProxy.action();
}
}
动态代理:(基于Cglib的动态代理\Enhancer方式)
如果真实类是一个普通类,没有实现接口,那么就采用这种方式, 创建出来真实类的子类作为代理类,是继承关系
测试实例:(同上)
/**
* 如果真实类是一个普通类,没有实现接口,那么就采用这种方式, 创建出来真实类的子类作为代理类。
*/
public class DynamicProxyCglibTest {
@Test
public void test(){
//目标类对象
final Songer songer = new Songer();
//创建代理对象
Enhancer enhancer = new Enhancer();
//设置父类
enhancer.setSuperclass(Songer.class);
//设置回调对象
enhancer.setCallback(new MethodInterceptor(){
/**
*
* @param o 代理对象
* @param method 方法对象的引用
* @param objects 方法参数
* @param methodProxy 方法对象的代理
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
actionBefore();
method.invoke(songer);
actionAfter();
return null;
}
});
//创建代理对象调用代理方法
Songer s = (Songer)enhancer.create();
s.action();
}
private void actionBefore(){
System.out.println("委托者(当前是经纪人)在演出之前执行前置工作");
}
private void actionAfter(){
System.out.println("委托者(当前是经纪人)在演出后执行后置工作");
}
}
}