10(结构型模式)java设计模式之代理模式

一、什么是代理模式

简介:代理模式是对象的结构模式。代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。

  • 为其他对象提供—种代理以控制对这个对象的访问,属于结构型模式。
  • 客户端并不直接调用实际的对象,而是通过调用代理,来间接的调用实际的对象

应⽤场景:

  • 各大数码专营店,代理厂商进行销售对应的产品,代理商持有真正的授权代理书
  • 客户端不想直接访问实际的对象,或者访问实际的对象存在困难,通过一个代理对象来完成间接的访问
  • 想在访问一个类时做一些控制,或者增强功能

二、代理模式的实现方式

模式结构分析:

  • Subject(抽象对象角色):抽象接口,真实对象和代理对象都要实现的一个抽象接口,好比销售数码产品
  • Proxy(代理对象角色):包含了对真实对象的引用,从而可以随意的操作真实对象的方法,好比代理加盟店
  • RealProject(目标对象角色):真实对象,好比厂商销售数码产品

类关系图:

统一模型:

代码实现:

查看代码
/*
* 抽取公共的⽅法
* */
public interface DigitalSell {
    void sell();
}
/*
*  真实的对象
* */
public class DigitalSellReal implements DigitalSell {
    @Override
    public void sell() {
        System.out.println("销售华为⼿机");
    }
}
/*
* 代理对象,增加了功能
* */
public class DigitalSellProxy implements DigitalSell {

    private DigitalSell realObj = new DigitalSellReal();
    @Override
    public void sell() {
        makeAddress();
        realObj.sell();
        makeAD();
    }
    private void makeAddress(){
        System.out.println("⼀个⼈流量很⾼的地址");
    }
    private void makeAD(){
        System.out.println("投放⼴告");
    }
}

测试用例:

/*
* 代理模式
* */
@Test
public void proxyDesign(){
    //真实对象的⾏为
    DigitalSell realObj = new DigitalSellReal();
    realObj.sell();
    //代理对象的⾏为
    DigitalSell proxy = new DigitalSellProxy();
    proxy.sell();
}

测试结果:

销售华为⼿机
⼀个⼈流量很⾼的地址
销售华为⼿机
投放⼴告

方法评估:

    和装饰器模式的区别

  • 代理模式主要是两个功能保护目标对象
  • 增强目标对象,和装饰模式类似了

优点:

  • 可以在访问一个类时做一些控制,或增加功能
  • 操作代理类无须修改原本的源代码,符合开闭原则,系统具有较好的灵活性和可扩展性

缺点:

  • 增加系统复杂性和调用链路

三、动态代理与静态代理

查看代码
 public class DigitalSellProxyFactory implements InvocationHandler {

    private Object target;
    //调用此工厂方法获得代理对象,其并不知道返回的是代理类对象还是委托类对象。
    public static DigitalSell getInstance(){
        return new DigitalSellProxy(new DigitalSellReal());
    }

    /**
     * 获取代理对象
     **/
    public Object newProxyInstance(Object targetObject){
        // 目标对象赋值
        this.target = targetObject;
        // 返回代理对象
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("=========="+method.getName()+"=============");
        System.out.println("------JDK动态代理开始-------");
        Object result = method.invoke(target, args);
        System.out.println("------JDK动态代理结束-------");

        return result;
    }
}
   /*
    * 代理模式
    * */
    @Test
    public void proxyDesign(){  
        System.out.println("-------------动态代理与静态代理-----------");
        //动态代理
        DigitalSellProxyFactory factory=new DigitalSellProxyFactory();
        DigitalSell realObjStatic= factory.getInstance();
        realObjStatic.sell();
        //静态代理
        DigitalSell sayHello = (DigitalSell) (factory.newProxyInstance(realObj));
        sayHello.sell();
    }

执行结果:

-------------动态代理与静态代理
⼀个⼈流量很⾼的地址
销售华为⼿机
投放⼴告
==========sell=============
------JDK动态代理开始-------
⼀个⼈流量很⾼的地址
销售华为⼿机
投放⼴告
------JDK动态代理结束-------

静态代理和动态代理的区别:

静态代理:由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。

动态代理:动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以不存在代理类的字节码文件。代理类和委托类的关系是在程序运行时确定。

静态代理缺点:

1)代理类和委托类实现了相同的接口,代理类通过委托类实现了相同的方法。这样就出现了大量的代码重复。如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。

2)代理对象只服务于一种类型的对象,如果要服务多类型的对象。势必要为每一种对象都进行代理,静态代理在程序规模稍大时就无法胜任了。

正因为静态代理有很多局限性,且编码起来没那么便捷,因此便出现了动态代理的方式。

四:知识点汇总

AOP: 面向切面编程,低耦合高内聚;底层原理采用动态代理方式

4.1在java里动态代理有两个实现方式:

参考:https://www.cnblogs.com/zhouchangyang/p/10920202.html

①针对有接口的类的代理,使用jdk中反射包下的动态代理

②针对没有接口的类的代理,使用第三方的jar包Enhancer

如果一个类既没有接口,又是final,那么不能进行增强

4.2动态代理步骤:

(原理参考:https://blog.csdn.net/jiankunking/article/details/52143504
1.创建一个实现接口InvocationHandler的类,它必须实现invoke方法
2.创建被代理的类以及接口
3.通过Proxy的静态方法
newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h)创建一个代理
4.通过代理调用方法

4.3在 Spring 的 AOP 代理下,只有目标方法由外部调用,目标方法才由 Spring 生成的代理对象来管理,这会造成自调用问题。

1.思路: 强制使用 AspectJ 对方法进行切面。

2.在本实现实现类中,添加该类的注入引用。

 

posted @ 2023-01-08 23:40  冰融心  阅读(22)  评论(0编辑  收藏  举报