设计模式学习笔记(14)——代理模式

版权声明:本文为博主原创,未经博主允许不得转载。 https://blog.csdn.net/weixin_36904568/article/details/90041182

1. 定义

为另一个对象提供一个代理对象,控制对这个对象的访问

2. 分类

  • 远程代理(另一个JVM的对象)
  • 虚拟代理(开销大的对象)
  • 保护代理(不安全的对象)
  • 缓存代理(减小开销)
  • 同步代理(多线程的安全访问)
  • 防火墙代理(保护网络资源)
  • 智能引用代理(引用某个对象时的处理)
  • 复杂隐藏代理
  • 写入时复制代理

3. 使用

  • 抽象对象:声明了目标对象和代理对象的共同接口,定义抽象的业务
  • 真正对象:被代理和被控制访问的对象,实现具体的业务
  • 代理对象:持有真正对象的引用,创建和销毁真正的对象、控制真正的对象

(1)远程代理

代理作为另一个JVM对象的本地代表,利用网络转发请求,在调用远程方法时作为替身

  • 服务器
    • 抽象对象
    • 真正对象
  • RMI代理对象
    • 客户辅助对象stub:打包调用信息,转发请求
    • 服务辅助对象skeleton:解开包,接收请求,调用方法,返回结果
  • 客户端:调用代理对象的方法
服务端:
  1. 定义抽象接口:定义业务方法(继承Remote、变量和返回值使用原语或序列化的类)
  2. 定义真正对象:实现业务方法(继承UnicastRemoteObject、构造器)、注册registry
  3. 产生代理对象:利用RMIC产生stub、skeleton
  4. 启动RMI registry:记录客户代理
  5. 远程服务
客户端:
  1. 获取代理对象stub:通过抽象接口,在服务器的registry寻找具体代理对象,返回stub
  2. 使用代理对象stub

(2)虚拟代理

代理作为创建开销大的对象的代表,在需要使用时才创建真正对象。在创建前和创建中都是由虚拟代理作为替身

  • 抽象对象:抽象的业务
  • 真正对象:实现业务方法
  • 代理对象:如果真正对象创建好了,则委托请求。否则开始新的线程创建真正对象,先提供默认实现
  • 客户端:调用抽象的业务方法
业务
package ProxyPattern;

/**
 * 抽象接口
 */
public interface Subject {
    public void operate();
}

package ProxyPattern;

/**
 * 真正对象
 */
public class RealSubject implements Subject {
    @Override
    public void operate() {
        System.out.println("真正的业务实现");
    }
}

代理
package ProxyPattern;

/**
 * 代理
 */
public class Proxy implements Subject{

    private RealSubject realSubject;

    @Override
    public void operate() {
        if (realSubject == null) {
            new Thread(){
                public void run(){
                    realSubject = new RealSubject();
                    System.out.println("创建完成");
                    realSubject.operate();
                }
            }.start();
            System.out.println("业务的默认实现");
        }
        else
            realSubject.operate();
    }
}

测试
package ProxyPattern;

public class Test {
    public static void main(String[] args) {
        Subject subject = new Proxy();
        System.out.println("首次调用");
        subject.operate();
//        System.out.println("第二次调用");
//        subject.operate();
    }
}

(3)保护代理

使用JAVA的动态代理,根据访问权限,决定用户能否访问对象的代理

  • 抽象对象:抽象的业务
  • 真正对象:实现具体的业务
  • 代理对象:持有真正对象的引用,控制真正的对象
  • 实际代理对象:代理收到方法后,请求实际工作的对象
    • 抽象对象
    • invoke(代理,方法名,参数) :判断方法能否执行
  • 客户端:根据真正对象获取其对应的代理对象
    • 创建代理+类加载器+代理实现接口+实际代理对象
业务
package ProxyPattern.ProtectProxy;

/**
 * 抽象接口
 */
public interface Subject {

    public void operateA();

    public void operateB();
}

package ProxyPattern.ProtectProxy;

/**
 * 真正对象
 */
public class RealSubject implements Subject {

    @Override
    public void operateA() {
        System.out.println("真正的业务实现A");
    }

    @Override
    public void operateB() {
        System.out.println("真正的业务实现B");
    }
}

代理对不同实体对象的具体处理过程
package ProxyPattern.ProtectProxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * 真正的代理处理过程
 */
public class MyInvocationHandler implements InvocationHandler {

    private Subject subject;

    public MyInvocationHandler(Subject subject){
        this.subject = subject;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
	    //对于实体RealSubject进行以下限制:
	    //对B结尾的方法进行保护,抛出异常
        //对A结尾的方法正常访问
        try {
            if (method.getName().endsWith("A"))
                return method.invoke(subject,args);
            if (method.getName().endsWith("B"))
                throw new Exception();
        }
        catch (Exception e){
            System.out.println("无法操作B有关的方法");
        }
        return null;
    }
}

测试
package ProxyPattern.ProtectProxy;

public class Test {
    public static void main(String[] args) {
        Subject subject = new RealSubject();
        Subject proxy = getProxy(subject);
        proxy.operateA();
        proxy.operateB();
    }

    //根据业务的类和接口以及自己实现的处理过程,获取代理
    static Subject getProxy(Subject subject){
        return (Subject) java.lang.reflect.Proxy.newProxyInstance(
                subject.getClass().getClassLoader(),
                subject.getClass().getInterfaces(),
                new MyInvocationHandler(subject)
        );
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_36904568/article/details/90041182
今日推荐