zoukankan      html  css  js  c++  java
  • 常见设计模式——代理模式

    Intent

    控制对其它对象的访问。

    Class Diagram

    抽象角色:声明真实对象和代理对象的共同接口,这样在任何使用真实对象的地方都可以使用代理对象。

    代理角色:代理对象内部含有真实对象的引用,从而可以在任何时候操作真实对象。代理对象和真实对象具有相同的接口,这样就可以在任何时候替代真实对象。代理对象通常在执行真实对象的操作前后,附加某些其他的操作,相当于对真实对象进行封装。

    真实角色:即为代理对象所代理的真实对象,是我们最终要引用的对象。

    Implementation

    // 抽象角色
    interface Subject{
        public void doSomething();
    }
    
    // 目标角色
    class RealSubject implements Subject{
        public void doSomething() {
            System.out.println("call doSomething()");
        }
    }
    
    // 代理角色
    class SubjectProxy implements Subject{
        // 代理持有目标对象的引用
        Subject subimpl = new RealSubject();
    
        public void doSomething() {
            System.out.println("before"); //调用目标对象之前可以做相关操作
            subimpl.doSomething();
            System.out.println("after");//调用目标对象之后可以做相关操作
        }
    }
    
    public class Test {
        public static void main(String[] args) throws Exception {
            Subject sub = new SubjectProxy();
            sub.doSomething();
        }
    }

    存在的问题:

    1. 如果 RealSubject 将来需要实现一个新的接口,就需要在代理类里再写该接口的实现方法,导致代理类的代码变得臃肿

    2. 当需要改变抽象角色接口时,无疑真实角色和代理角色也需要改变。

    JDK动态代理

    package com.eastern.msap.test;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    interface Subject {
        public void doSomething();
    }
    
    class RealSubject implements Subject {
        public void doSomething() {
            System.out.println("call doSomething()");
        }
    }
    
    class ProxyHandler implements InvocationHandler {
    
        private Object target;
    
        public ProxyHandler(Object target) {
            this.target = target;
        }
    
        public Object getProxyInstance() {
    
            return Proxy.newProxyInstance(
                    target.getClass().getClassLoader(),
                    target.getClass().getInterfaces(),// 绑定该类实现的所有接口,取得代理类
                    this);
        }
    
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Object result;
            System.out.println("在调用具体函数方法前,执行功能处理");
            result = method.invoke(target, args);
            System.out.println("在调用具体函数方法后,执行功能处理");
            return result;
        }
    }
    
    public class Test {
        public static void main(String args[]) {
            ProxyHandler proxyHandler = new ProxyHandler(new RealSubject());
            Subject sub = (Subject) proxyHandler.getProxyInstance();
            sub.doSomething();
        }
    }
    在调用具体函数方法前,执行功能处理
    call doSomething()
    在调用具体函数方法后,执行功能处理

    对于问题一,因为JDK动态代理是根据目标对象实现的所有接口生成代理类对象的,所以如果目标对象需要实现新接口时,生成代理类的代码不用做更改。

    对于问题二,当接口改变的时候,虽然【被代理类】需要改变,生成代理类的代码也不用更改。

    这个调用虽然足够灵活,可以动态生成一个具体的代理类,而不用自己显式的创建一个实现具体接口的代理类。

  • 相关阅读:
    SQL Server SQLHelper帮助类
    Winform 常用的方法
    SQL Server 插入含有中文字符串出现乱码现象的解决办法
    ComboBox 中 DisplayMember 和 ValueMember 都是具体干什么的?
    HTML常用标签属性使用
    虚拟机安装windows server 2012 R2
    VS2017生成带图标的QT项目方法
    QSS 记录
    QT qss资源文件与代码分离
    pgsql 服务遇见的问题记录
  • 原文地址:https://www.cnblogs.com/codestarer/p/13635529.html
Copyright © 2011-2022 走看看