• Java 静态代理


    Java 静态代理

    静态代理通常用于对原有业务逻辑的扩充。比如持有二方包的某个类,并调用了其中的某些方法。然后出于某种原因,比如记录日志、打印方法执行时间,但是又不好将这些逻辑写入二方包的方法里。所以可以创建一个代理类实现和二方方法相同的方法,通过让代理类持有真实对象,然后在原代码中调用代理类方法,来达到添加我们需要业务逻辑的目的。

    这其实也就是代理模式的一种实现,通过对真实对象的封装,来实现扩展性。

    一个典型的代理模式通常有三个角色,这里称之为**代理三要素**

    package singleton;

    public class TestProxy {
    public static void main(String[] args) {
    Subject subject = new ProxySubject();
    subject.request();
    }
    }

    抽象角色

    abstract class Subject {
    public abstract void request();
    }

    真实角色

    class RealSubject extends Subject {
    @Override
    public void request() {
    System.out.println("From real subject");
    }

    }

    代理角色

    class ProxySubject extends Subject {
    private RealSubject realSubject;// 代理角色内部引用了真是角色

    @Override
    public void request() {
    this.preRequest();// 在真实角色操作之前所附加的操作
    if (null == realSubject) {
    realSubject = new RealSubject();
    }
    realSubject.request();// 真实角色锁完成的事情
    this.postRequest();// 在真实角色操作之后所附加的操作
    }

    private void preRequest() {
    System.out.println("pre request");
    }

    private void postRequest() {
    System.out.println("post request");
    }

    }

    运行结果:

    pre request
    From real subject
    post request

    也可以用接口表示抽象角色

    共同接口

    public interface Action {
        public void doSomething();
    }
    

    真实对象

    public class RealObject implements Action{
    
        public void doSomething() {
            System.out.println("do something");
        }
    }
    

    代理对象

    public class Proxy implements Action {
        private Action realObject;
    
        public Proxy(Action realObject) {
            this.realObject = realObject;
        }
        public void doSomething() {
            System.out.println("proxy do");
            realObject.doSomething();
        }
    }
    

    运行代码

        Proxy proxy = new Proxy(new RealObject());
        proxy.doSomething();
    

    simple_proxy.png

    这种代理模式也最为简单,就是通过proxy持有realObject的引用,并进行一层封装。

    静态代理的优点和缺点

    先看看代理模式的优点: 扩展原功能,不侵入原代码。

    再看看这种代理模式的缺点:

    假如有这样一个需求,有十个不同的RealObject,同时我们要去代理的方法是不同的,比要代理方法:doSomething、doAnotherThing、doTwoAnotherThing,添加代理前,原代码可能是这样的:

    realObject.doSomething();
    realObject1.doAnotherThing();
    realObject2.doTwoAnother();
    

    为了解决这个问题,我们有方案一:

    为这些方法创建不同的代理类,代理后的代码是这样的:

    proxy.doSomething();
    proxy1.doAnotherThing();
    proxy2.doTwoAnother();
    

    当然,也有方案二:

    通过创建一个proxy,持有不同的realObject,实现Action1、Action2、Action3接口,来让代码变成这样:

    proxy.doSomething();
    proxy.doAnotherThing();
    proxy.doTwoAnother();
    

    于是你的代理模型会变成这样:

    dynamic_proxy.png

    毫无疑问,仅仅为了扩展同样的功能,在方案一种,我们会重复创建多个逻辑相同,仅仅RealObject引用不同的Proxy。

    而在方案二中,会导致proxy的膨胀,而且这种膨胀往往是无意义的。此外,假如方法签名是相同的,更需要在调用的时候引入额外的判断逻辑。

    package Test;

    public class TestProxy {
    public static void main(String[] args) {
    Action1 action1 = new ProxySubject();
    action1.requestFirstThing();
    Action2 action2 = new ProxySubject();
    action2.requestSecondThing();
    Action3 action3 = new ProxySubject();
    action3.requestThirdThing();

    }
    }

    interface Action1 {
    void requestFirstThing();
    }

    interface Action2 {
    void requestSecondThing();
    }

    interface Action3 {
    void requestThirdThing();
    }

    class RealSubject1 implements Action1 {
    @Override
    public void requestFirstThing() {
    System.out.println("From real subject1");
    }

    }

    class RealSubject2 implements Action2 {

    @Override
    public void requestSecondThing() {
    System.out.println("From real subject2");
    }
    }

    class RealSubject3 implements Action3 {

    @Override
    public void requestThirdThing() {
    System.out.println("From real subject3");
    }
    }

    class ProxySubject implements Action1, Action2, Action3 {
    private RealSubject1 realSubject1;// 代理角色内部引用了真是角色
    private RealSubject2 realSubject2;// 代理角色内部引用了真是角色
    private RealSubject3 realSubject3;// 代理角色内部引用了真是角色

    @Override
    public void requestFirstThing() {
    this.preRequest();// 在真实角色操作之前所附加的操作
    if (null == realSubject1) {
    realSubject1 = new RealSubject1();
    }
    realSubject1.requestFirstThing();// 真实角色锁完成的事情
    this.postRequest();// 在真实角色操作之后所附加的操作
    }

    private void preRequest() {
    System.out.println("pre request");
    }

    private void postRequest() {
    System.out.println("post request");
    }

    @Override
    public void requestThirdThing() {
    this.preRequest();// 在真实角色操作之前所附加的操作
    if (null == realSubject2) {
    realSubject2 = new RealSubject2();
    }
    realSubject2.requestSecondThing();// 真实角色锁完成的事情
    this.postRequest();// 在真实角色操作之后所附加的操作

    }

    @Override
    public void requestSecondThing() {
    this.preRequest();// 在真实角色操作之前所附加的操作
    if (null == realSubject3) {
    realSubject3 = new RealSubject3();
    }
    realSubject3.requestThirdThing();// 真实角色锁完成的事情
    this.postRequest();// 在真实角色操作之后所附加的操作
    }
    }

    运行结果:

    pre request
    From real subject1
    post request
    pre request
    From real subject3
    post request
    pre request
    From real subject2
    post request

  • 相关阅读:
    【字符串处理算法】字符串包含的算法设计及C代码实现【转】
    linux中字符串转换函数 simple_strtoul【转】
    Linux内核空间内存申请函数kmalloc、kzalloc、vmalloc的区别【转】
    linux非阻塞的socket EAGAIN的错误处理【转】
    嵌入式 uboot引导kernel,kernel引导fs【转】
    jQuery入门(4)jQuery中的Ajax应用
    jQuery入门(3)事件与事件对象
    jQuery入门(2)使用jQuery操作元素的属性与样式
    jQuery入门(1)jQuery中万能的选择器
    JavaScript在IE6下超级链接window.location.href不跳转的bug 及 解决方案
  • 原文地址:https://www.cnblogs.com/erma0-007/p/8653214.html
Copyright © 2020-2023  润新知