天天看点

吐槽一下静态代理和装饰者模式的区别

今天我们来聊聊静态代理模式和装饰者模式的区别。一开始见到这两个模式的时候,第一感觉就是两个模式的实现方式不是大同小异么,然后带着疑惑在网上搜了搜资料,看到很多资料说他们区别于:

代理模式主要目的在控制对象的访问。装饰者模式主要目的在于增加对象的行为。其实这句话是没错的。但是例举的例子就让人很摸不清头脑了,大概意思就是代理对象在编译期就已经确定了,而装饰者模式的装饰对象是在程序运行过程中才确定的。下面来贴两段代码:

//代理模式
public class Proxy implements Subject{

       private Subject subject;
       public Proxy(){
             //关系在编译时确定
            subject = new RealSubject();
       }
       public void doAction(){
             ….
             subject.doAction();
             ….
       }
}

//装饰器模式
public class Decorator implements Component{
        private Component component;
         //装饰对象在运行过程中传入
        public Decorator(Component component){
            this.component = component
        }
       public void operation(){
            ….
            component.operation();
            ….
       }
}
           

拿上面两段代码来举例,很多人都说,上面两段代码贴的就是代理模式和装饰者模式的区别。因为在我们的代理类中,在构造方法里,隐藏了一个被代理对象的实例化的过程,在装饰者模式中被装饰的对象是由构造方法中传入的。

这么说我是不敢苟同的。在《Head First设计模式》一书中在介绍代理模式的时候有这样一个例子,简单贴一下代码:

public class ImagetProxy implements Icon {

    private ImageIcon imageIcon;

    private String url;

    public ImagetProxy(String url) {
        this.url = url;
    }

    @Override
    public int getIconHeight() {
        if (imageIcon == null) {
            return 100;
        } else {
            return imageIcon.getIconHeight();
        }

    }

    @Override
    public int getIconWidth() {
        if (imageIcon == null) {
            return 100;
        } else {
            return imageIcon.getIconWidth();
        }
    }

    @Override
    public void partIcon() {
        if (imageIcon != null) {
            imageIcon.partIcon();
        } else {
            imageIcon = new ImageIcon(url);
        }
    }
}

           

上述代码中的被代理对象是ImageIcon,但是ImageIcon的对象的确立是通过传入的url来确定的,是在程序运行过程中确定的。

再例举《Android源码设计模式解析与实战》书中介绍代理模式的例子:

public abstract class Subject {

    public abstract void visit();

}


public class SubjectProxy extends Subject {


    private RealSubject subject;

    public SubjectProxy(RealSubject subject) {
        this.subject = subject;
    }

    @Override
    public void visit() {
        subject.visit();
    }
}

           

同样的代理对象还是通过构造方法传入的。并不是所谓的在编译期就确定了。

就我们的面向对象的基本原则来看,如果我们的被代理对象,在代理对象的构造方法就被实例化了,就确定了代理对象,那就不符合我们面向对象的基本原则了。

程序失去了扩展性,耦合性也比较高。举个例子,如果我们被代理对象的构造方法发生了变更,

那我们的代理类,就要去修改。

好比我们找律师打官司,律师就是我们的代理,每个找律师打官司的人的诉求是不一样的,我们不可能说,找律师的打官司的人一开始就被确定了。

在我看来,是代理模式还是装饰者模式,是否是对对象增加了控制的访问或者是否是对对象增加装饰的行为,是通过我们的应用场景来分析的。并不是通过是否在代理对象或者装饰的构造方法中传入被代理对象或被装饰者对象,来判断的。