「设计模式」代理模式

224 阅读3分钟

定义

代理模式简单来说就是为其他对象提供一种代理以控制对这个对象的访问.

使用场景

当无法或者不想直接访问某个对象或访问某个对象存在困难时可以通过一个代理对象来间接访问,为了保证客户端使用的透明性,委托对象与代理对象需要实现相同的接口

静态代理

UML 类图

代理模式Uml.png

代码实现

抽象主题类

/***
 * 抽象主题类
 * 该类主要的职责是声明真实主题与代理的共同接口方法,该类既可以是一个抽象类,也可以是一个接口
 */
public abstract class Subject {
    //一个普通的业务方法
    public abstract void visit();
}

实现抽象主题的真实主题类

/***
 * 实现抽象主题的真实主题类
 * 该类是被委托类或被代理类,该类定义了代理所标识的真实对象,由其执行具体的业务逻辑方法,
 * 而客户类则通过代理类间接的调用真实主题类中定义的方法
 */
public class RealSubject extends Subject {
    @Override
    public void visit() {
        System.out.println("Real subject visit");
    }
}

代理类

/***
 * 代理类
 * 此类为委托类或代理类,该类持有一个真实主题类的引用,在其所实现的接口方法中调用主题类
 * 中相应的接口方法,以此起到代理的作用
 */
public class ProxySubject extends Subject{
    private RealSubject realSubject;

    public ProxySubject(RealSubject realSubject) {
        this.realSubject = realSubject;
    }

    @Override
    public void visit() {
        realSubject.visit(); // 代理类通过真实主题对象的引用调用其方法
    }
}

具体客户类

/***
 * 具体客户类
 */
public class Client {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        ProxySubject proxySubject = new ProxySubject(realSubject);
        proxySubject.visit();
    }

}

代理模式输出.png

图片中可以看到输出的是 我们真实代理类中的输出内容.

动态代理

代码实现

动态代理类接口定义

/***
 * 动态代理类接口
 */
public interface Dynamic {
    void visit();
}

代理类具体实现

/***
 * 动态代理类实现
 */
public class DynamicSubject  implements Dynamic{

    @Override
    public void visit() {
        System.out.println("动态代理了输出 DynamicSubject");
    }
}

接下来我们看下代理类代码

//主要是通过invoke方法来调用具体被代理类的方法
public class DynamicProxy implements InvocationHandler {
    private Object object;  //被代理对象的引用

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

    @Override
    public Object invoke(Object o, Method method, Object[] args) throws Throwable {
        //调用被代理对象的方法
       Object result = method.invoke(object, args);
        return result;
    }
}

接下来看下客户端类

/***
 * 具体客户类
 */
public class Client {
    public static void main(String[] args) {
        DynamicSubject dynamicSubject = new DynamicSubject();
        //因为代理类持有的引用是Object ,因此我们可以更具业务创建多种被代理对象.
        DynamicProxy dynamicProxy = new DynamicProxy(dynamicSubject);
        //获取被代理类的ClassLoader
        ClassLoader loader = dynamicSubject.getClass().getClassLoader();
        Dynamic dynamic = (Dynamic) Proxy.newProxyInstance(loader,new Class[]{Dynamic.class},dynamicProxy);
        dynamic.visit();
    }

}

运行后输出:

动态代理了输出 DynamicSubject

总结

  • 代理模式主要分为两种,一种是静态代理,二是动态代理:

  • 静态代理在运行代码前代理类的class编译文件已经存在了.

  • 动态代理则是通过反射机制动态生成代理者对象. 在实际开发中动态代理运用的比较多.

优点

  • 职责清晰,真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务,通过后期的代理完成一件完成事务,附带的结果就是编程简洁清晰。
  • 代理对象可以在客户端和目标对象之间起到中介的作用,这样起到了中介的作用和保护了目标对象的作用。
  • 高扩展性

缺点

  • 类代码量增加