Java设计模式之代理模式

本文详细介绍了Java设计模式中的代理模式,包括静态代理和动态代理。静态代理通过创建代理类来间接调用真实对象的方法,而动态代理则在运行时动态生成代理对象,无需预先定义具体的代理类。动态代理利用Java的Proxy类和InvocationHandler接口,能够更灵活地处理多个接口方法。文中通过服装店和手机销售的实例展示了代理模式的应用。
摘要由CSDN通过智能技术生成


1. 概述

  • 代理设计模式的原理:

使用一个代理将对象包装起来, 然后用该代理对象取代原始对象。任何对原
始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原
始对象上。

  • 代理模式:给某对象提供一个代理以控制对该对象的访问。
  • 代理对象作为访问对象和目标对象之间的中介,访问对象不适合或者不能直接引用目标对象。
  • 分为动态代理和静态代理两种。
  • 举例:比如在购买衣服时,我们通常是在服装店买而不是去生成衣服的服装厂去购买,服装店就是服装厂的一个代理类,代理类可以在执行被代理类的过程中进行功能扩展 (加钱)。
优点:
    代理模式在客户端与目标对象之间起到一个中介作用和保护目标对象的作用;
    代理对象可以扩展目标对象的功能;
    代理模式能将客户端与目标对象分离,在一定程度上降低了系统的耦合度;
 
缺点:
    增加了系统的复杂度;

2. 主要角色

  • 抽象主题(Subject)类: 通过接口或抽象类声明真实主题和代理对象实现的业务方法。
  • 真实主题(Real Subject)类: 实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。
  • 代理(Proxy)类 : 提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或扩展真实主题的功能。

3. 静态代理

代理类和被代理类在编译期间确定。


使用示例1:服装店只卖一种衣服 (专卖店)

//抽象主题类

interface ClothFactory{ // 服装厂接口
    void sellCloth();
}

//真实主题类(被代理类)

class FirstClothFactory implements ClothFactory{ // First品牌服装厂
    @Override
    public void sellCloth() {
        System.out.println("First工厂售卖服装...");
    }
}

//代理类

  • 代理类中声明被代理类的对象,并实现抽象主题类接口
class ProxyFirstClothFactory implements ClothFactory{ // First品牌服装代理商
    //声明被代理类对象
    private FirstClothFactory firstClothFactory;
    public ProxyFirstClothFactory(ClothFactory factory){
        this.firstClothFactory = (FirstClothFactory) factory;
    }
    //等同于private FirstClothFactory firstClothFactory = new FirstClothFactory();
    @Override
    public void sellCloth() {
        System.out.println("代理商的准备工作...");
        firstClothFactory.sellCloth();
        System.out.println("代理商的后续工作...");
    }
}

//测试

//创建代理类对象
ProxyFirstClothFactory proxyFirstClothFactory = new ProxyFirstClothFactory(new FirstClothFactory());
//调用代理类对象的方法
proxyFirstClothFactory.sellCloth();

使用示例2:服装店卖多种衣服 (多个被代理类)

//抽象主题类
interface ClothFactory{ // 服装厂接口
    void sellCloth();
}

//真实主题类(被代理类)
class FirstClothFactory implements ClothFactory{ // First品牌服装厂
    @Override
    public void sellCloth() {
        System.out.println("First工厂售卖服装...");
    }
}

//真实主题类(被代理类)
class SecondClothFactory implements ClothFactory{ // Second品牌服装厂
    @Override
    public void sellCloth() {
        System.out.println("Second工厂售卖服装...");
    }
}

//代理类

//代理类
class ProxyClothFactory implements ClothFactory{ // 品牌服装代理商
    //声明被代理类对象
    private ClothFactory clothFactory;
    public ProxyClothFactory(ClothFactory factory){
        this.clothFactory = factory;
    }
    @Override
    public void sellCloth() {
        System.out.println("代理商的准备工作...");
        clothFactory.sellCloth();
        System.out.println("代理商的后续工作...");
    }
}

//测试

//创建代理类对象
ProxyClothFactory proxyClothFactory = new ProxyClothFactory(new FirstClothFactory());
//调用代理类方法
proxyClothFactory.sellCloth();
//创建代理类对象
ProxyClothFactory proxyClothFactory1 = new ProxyClothFactory(new SecondClothFactory());
//调用代理类方法
proxyClothFactory1.sellCloth();

//测试结果:
//代理商的准备工作...
//First工厂售卖服装...
//代理商的后续工作...
//代理商的准备工作...
//Second工厂售卖服装...
//代理商的后续工作...

4. 动态代理

要求必须定义接口,对接口进行代理。

  • 动态代理相比于静态代理的优点:

抽象角色中(接口)声明的所有方法都被转移到调用处理器一个集中的方法中处理,这样,我们可以更加灵活和统一的处理众多的方法。

  • 动态代理没有在编译时期显式的定义代理类
  • 在运行的时候根据传进来的被代理类的对象,动态的创建代理类 (不用自己写代理类),体现出反射的动态性。
  • 动态代理需要解决的问题:
    1. 如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象。
    2. 当通过代理类的对象调用方法a时,如何动态的去调用被代理类中的同名方法a。
  • 在Java中提供了一个动态代理类Proxy,Proxy提供了一个创建代理对象的静态方法:newProxyInstance()用来获取代理对象。

//使用Proxy获取代理对象:

newProxyInstance()方法参数说明:
    ClassLoader loader : 类加载器,用于加载代理类,使用真实对象的类加载器即可
    Class<?>[] interfaces : 真实对象所实现的接口,代理模式真实对象和代理对象实现相同的接口
    InvocationHandler h : 代理对象的调用处理程序

InvocationHandler接口中的invoke():

InvocationHandler中invoke方法参数说明:
    proxy : 代理对象
    method : 对应于在代理对象上调用的接口方法的 Method 实例
    args : 代理对象调用接口方法时传递的实际参数

使用示例1:同时代理售卖服装和手机

//服装被代理类

//抽象主题类
interface ClothFactory{ // 服装厂接口
    void sellCloth();
}

//真实主题类(被代理类)
class ProxyFirstClothFactory implements ClothFactory{ // First品牌服装厂
    @Override
    public void sellCloth() {
        System.out.println("First工厂售卖服装...");
    }
}

//真实主题类(被代理类)
class ProxySecondClothFactory implements ClothFactory{ // Second品牌服装厂
    @Override
    public void sellCloth() {
        System.out.println("Second工厂售卖服装...");
    }
}

//手机被代理类

//抽象主题类
interface PhoneFactory{ // 手机制造商接口
    void sellPhone();
}

//真实主题类(被代理类)
class ProxyPhoneFactory implements PhoneFactory{ // 手机制造商(被代理类)
    @Override
    public void sellPhone() {
        System.out.println("手机代理商卖手机...");
    }
}

自定义InvocationHandler接口的实现类

class MyInvocationHandler implements InvocationHandler {
    private Object obj; // 使用被代理类的对象进行赋值
    public void bind(Object obj){ // 传递被代理类的对象
        this.obj = obj;
    }
    //当通过代理类的对象,调用方法时,就会自动的调用invoke()方法
    //需要将被代理类要执行的方法的功能声明在invoke()中
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //method:即为代理类对象调用的方法,也就作为了被代理类对象要调用的方法。
        //obj:被代理类的对象。
        Object returnValue = method.invoke(obj,args); // 传递被代理类的对象和同名方法的参数args
        //method方法的返回值就作为当前类中的invoke()的返回值。
        return returnValue;
    }
}

//获取代理类对象的工厂类
//Proxy.newProxyInstance()返回代理类对象

//动态创建代理类对象
class ProxyFactory{
    //调用此静态方法,动态创建代理类对象进行返回。
    public static Object getProxyInstance(Object obj){ // obj:传递被代理类的对象
        MyInvocationHandler myInvocationHandler = new MyInvocationHandler();
        myInvocationHandler.bind(obj); // 传递被代理类的对象
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),myInvocationHandler);
    }
}

//测试

//创建被代理类对象
ProxyFirstClothFactory proxyFirstClothFactory = new ProxyFirstClothFactory();
ProxySecondClothFactory proxySecondClothFactory = new ProxySecondClothFactory();
ProxyPhoneFactory proxyPhoneFactory = new ProxyPhoneFactory();
//创建代理类对象
//得到一个与被代理类实现相同接口的代理类对象
ClothFactory proxyInstance1 = (ClothFactory) ProxyFactory.getProxyInstance(proxyFirstClothFactory);
proxyInstance1.sellCloth(); // First工厂售卖服装...
ClothFactory proxyInstance2 = (ClothFactory) ProxyFactory.getProxyInstance(proxySecondClothFactory);
proxyInstance2.sellCloth(); // Second工厂售卖服装...
PhoneFactory proxyInstance3 = (PhoneFactory) ProxyFactory.getProxyInstance(proxyPhoneFactory);
proxyInstance3.sellPhone(); // 手机代理商卖手机...

使用示例2:另外一种写法逻辑

//代理类直接实现InvocationHandler接口

class ProxyFactory implements InvocationHandler {

    private final Object obj; // 被代理类对象
    public ProxyFactory(Object obj) { // 传递被代理类对象
        this.obj = obj;
    }
    //调用代理对象的方法时进入invoke()
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //method为调用代理对象的方法,args是参数数组
        Object returnValue = method.invoke(obj,args); // 传递被代理类的对象和同名方法的参数args
        //method方法的返回值就作为当前类中的invoke()的返回值。
        return returnValue;
    }
}

//测试

//创建被代理类对象
ProxyPhoneFactory proxyPhoneFactory = new ProxyPhoneFactory();
//获取代理类对象
//得到一个与被代理类实现相同接口的代理类对象
InvocationHandler handler = new ProxyFactory(proxyPhoneFactory);
PhoneFactory phoneFactory = (PhoneFactory) Proxy.newProxyInstance(
        proxyPhoneFactory.getClass().getClassLoader(), // 被代理类的类加载器
        proxyPhoneFactory.getClass().getInterfaces(), // 被代理类的接口列表
        handler // 代理对象处理逻辑
);
//代理类对象调用方法
phoneFactory.sellPhone(); // 手机代理商卖手机...

5. CGLIB动态代理


如有错误,欢迎指正!


——————END-2022-06-20——————

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

苡荏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值