代理模式(Proxy Pattern)

z_coding發表於2024-05-28

1. 簡介

代理模式屬於設計模式中的結構型模式,有靜態代理和動態代理兩種實現方式。代理模式使用代理類來控制訪問委託類中方法或者增強委託類的功能。

2. 實現

靜態代理

靜態代理即是代理類在編譯期間已知。

UML類圖

UML類圖
如上圖所示:

  • Subject介面定義了代理類Proxy和委託類RealSubject共同的方法request()
  • RealSubject委託類,它是被代理和控制訪問的物件
  • Proxy代理類引用了RealSubject的物件,實現了對它的訪問控制

程式碼實現

interface Subject{
    void request();
}


class RealSubject implements Subject{
    @Override
    public void request() {
        System.out.println("request");
    }

    public void run(){
        System.out.println("run");
    }
}

class Proxy implements Subject{
    private Subject subject;

    public Proxy(Subject subject){
        this.subject = subject;
    }

    @Override
    public void request() {
        System.out.println("before");
        subject.request();
        System.out.println("after");
    }
}
複製程式碼

動態代理

動態代理即是代理類在執行期間產生,這個需要用到Java的反射機制,使用JDK的java.lang.reflect這個包中的一個介面和類:

  • InvocationHandler介面是個呼叫處理器,通過重寫invoke(Object proxy, Method method, Object[] args)方法來對委託類中的方法進行控制訪問。
  • Proxy類提供幾個靜態方法:
    • getProxyClass(ClassLoader loader, Class<?>... interfaces)方法通過傳入類載入器和委託類實現的介面這些引數來生成一個代理類,生成的代理類繼承了Proxy並且實現了所有委託類的介面
    • newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)方法建立一個代理類例項

程式碼實現

interface Subject{
    void request();
}

/委託類
class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("request");
    }

    public void run(){
        System.out.println("run");
    }
}

/呼叫處理器
class ProxyInvocationHandler implements InvocationHandler{

    private Object realSubject;
    
    public ProxyInvocationHandler(Object realSubject){
        this.realSubject = realSubject;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before");
        Object returnObject = method.invoke(realSubject, args);
        System.out.println("after");
        return returnObject;
    }
}

class ProxyClass {

    private Class<?> proxy;
    private ProxyInvocationHandler handler;
    private Object realSubject;

    public ProxyClass(ProxyInvocationHandler handler, Object realSubject) {
        this.handler = handler;
        this.realSubject = realSubject;
        this.proxy = productProxyClass();
    }
    
    /產生代理類
    private Class<?> productProxyClass() {
        ClassLoader loader = ClassLoader.getSystemClassLoader();
        Class<?>[] interfaces = realSubject.getClass().getInterfaces();

        return Proxy.getProxyClass(loader, interfaces);
    }

    public Class<?> getProxy() {
        return proxy;
    }

    /建立代理類物件
    public Object newInstance() {
        try {
            Constructor constructor = proxy.getDeclaredConstructor(InvocationHandler.class);
            return constructor.newInstance(handler);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

        return null;
    }
}

public class DynamicProxy{
    public static void main(String[] args){
        /建立委託類物件
        Subject realSubject = new RealSubject();
        /建立代理類呼叫處理器
        ProxyInvocationHandler handler = new ProxyInvocationHandler(realSubject);
        
        ProxyClass proxyClass = new ProxyClass(handler, realSubject);
        生成代理類物件
        Subject proxy = (Subject) proxyClass.newInstance();
        
        proxy.request();
    }
}
複製程式碼

相關文章