Android开发经验谈Android开发

26 Java设计模式系列-代理模式

2021-01-23  本文已影响0人  凤邪摩羯

代理模式

代理模式是非常常见的设计模式之一,写个笔记,记录一下我的学习过程和心得。

首先了解一些代理模式的定义。

为其他对象提供一种代理以控制这个对象的访问。

涉及角色及说明:

Subject(抽象主题类):接口或者抽象类,声明真实主题与代理的共同接口方法。
RealSubject(真实主题类):也叫做被代理类或被委托类,定义了代理所表示的真实对象,负责具体业务逻辑的执行,客户端可以通过代理类间接的调用真实主题类的方法。
Proxy(代理类):也叫委托类,持有对真实主题类的引用,在其所实现的接口方法中调用真实主题类中相应的接口方法执行。
Client(客户端类):使用代理模式的地方。

理解:

以海外代购为例,在国内的人想买国外的东西只能去找国外的人去进行代购。

1 创建抽象主题类

人都是有购买这个方法的:

/**
 * 抽象主题类: 指代理角色和真实角色对外提供的公共方法,一般为一个接口
 */
public interface BuyToolInterface {


    void buy();//定义买的功能:

}

2 创建真实主题类

/**
 * 真实主题类: 需要实现抽象角色接口,定义了真实角色所要实现的业务逻辑,以便供代理角色调用。也就是真正的业务逻辑在此
 */
public class Domestic implements BuyToolInterface {

    // 国内的人想购买某些产品,定义具体的购买过程
    @Override
    public void buy() {//具体实现
        System.out.println("按需求买一个包");
    }
}

3 创建代理类

    
/**
 * 代理角色类: 需要实现抽象角色接口,定义了真实角色所要实现的业务逻辑,以便供代理角色调用。也就是真正的业务逻辑在此
 */
public class Oversea implements BuyToolInterface {
    BuyToolInterface mBuyToolInterface;//持有People类的引用

    public Oversea(BuyToolInterface buyToolInterface) {
        mBuyToolInterface = buyToolInterface;
    }

    @Override
    public void buy() {
        System.out.println("前置操作:");
        mBuyToolInterface.buy();//调用了真实角色的buy()方法,
        System.out.println("后置操作:");

    }
}

5 客户端测试:

     public void test() {
        BuyToolInterface domestic = new Domestic();        //创建国内购买人
        BuyToolInterface oversea = new Oversea(domestic);  //创建海外代购类并将domestic作为构造函数传递
        oversea.buy();
    }

输出结果:

前置操作:
按需求买一个包
后置操作:

静态代理与动态代理

从代码的角度来分,代理可以分为两种:一种是静态代理,另一种是动态代理。

1 创建动态代理类
public class DynamicProxy implements InvocationHandler {//实现InvocationHandler接口
    private Object obj;//持有真实对象(该对象进行代理操作)

    public DynamicProxy(Object obj) {
        this.obj = obj;
    }

    //重写invoke()方法
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("前置操作:");
        Object result = method.invoke(obj, args);//调用被代理的对象的方法
        System.out.println("后置操作:");

        return result;
    }
}

2 修改客户端的测试方法:
    public void test() {
        BuyToolInterface domestic = new Domestic();                                 //创建国内购买人
        DynamicProxy proxy = new DynamicProxy(domestic);                  //创建动态代理
        ClassLoader classLoader = domestic.getClass().getClassLoader();   //获取ClassLoader
        BuyToolInterface buyToolInterface = (BuyToolInterface) Proxy.newProxyInstance(classLoader, new Class[]{BuyToolInterface.class}, proxy); //通过 Proxy 创建海外代购实例 ,实际上通过反射来实现的。
        buyToolInterface.buy();//调用真实角色的buy()
  
   }

输出结果:

前置操作:
按需求买一个包
后置操作:

静态代理与动态代理比较

静态代理的缺点:

静态代理如果接口新增一个方法,除了所有实现类(真实主题类)需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
代理对象只服务于一种类型的对象,如果要服务多类型的对象。必须要为每一种对象都进行代理,静态代理在程序规模稍大时就无法胜任了。

动态代理的优点:

可以通过一个代理类完成全部的代理功能,接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler.invoke)。当接口方法数量较多时,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。
动态代理的应用使我们的类职责更加单一,复用性更强。

动态代理的缺点:

不能对类进行代理,只能对接口进行代理,如果我们的类没有实现任何接口,那么就不能使用这种方式进行动态代理(因为$Proxy()这个类集成了Proxy,Java的集成不允许出现多个父类)。

广泛应用

总结

总结一下代理模式的优缺点

优点

代理作为调用者和真实主题的中间层,降低了模块间和系统的耦合性。
可以以一个小对象代理一个大对象,达到优化系统提高运行速度的目的。
代理对象能够控制调用者的访问权限,起到了保护真实主题的作用。

缺点

由于在调用者和真实主题之间增加了代理对象,因此可能会造成请求的处理速度变慢。
实现代理模式需要额外的工作(有些代理模式的实现非常复杂),从而增加了系统实现的复杂度。

适用场景

当一个对象不能或者不想直接访问另一个对象时,可以通过一个代理对象来间接访问。为保证客户端使用的透明性,委托对象和代理对象要实现同样的接口。
被访问的对象不想暴露全部内容时,可以通过代理去掉不想被访问的内容。

根据适用范围,代理模式可以分为以下几种:

上一篇 下一篇

猜你喜欢

热点阅读