【设计模式】——装饰器模式VS代理模式

最近在学习Spring源码,尤其是在学习FactoryBean的时候,有涉及到装饰器模式,再结合自己之前学习的设计模式,代理模式觉得和装饰器模式很相似,但是仔细研究后有各有不同,在这篇文章中整理下,希望可以帮助到需要的朋友。

装饰器模式

定义:动态地给一个对象添加一些额外的职责,同时又不改变其结构,就增加功能来说装饰模式比生成子类更为灵活。

【设计模式】——装饰器模式VS代理模式_第1张图片

Component是定义一个对象接口,可以给这些对象动态的添加职责,ConcreteComponent是定义一个具体的对象,也可以给这个对象动态添加一些职责。Decorator,装饰抽象类,继承Component,从外类来扩展Component类的功能,但对于Component来说,是无需知道Decorator的存在的。至于ConcreteDecorator就是具体的装饰对象,起到给Component添加职责的功能。

主要解决:一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。

何时使用:在不想增加很多子类的情况下扩展类。

如何解决:将具体功能职责划分,同时继承装饰者模式。

关键代码: 1、Component 类充当抽象角色,不应该具体实现。 2、修饰类引用和继承 Component 类,具体扩展类重写父类方法。

优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。

缺点:多层装饰比较复杂。

使用场景: 1、扩展一个类的功能。 2、动态增加功能,动态撤销。

注意事项:可代替继承。

实现代码

//充当抽象角色,不应该具体实现
public interface Component {

    void Operation();
}

//有一个具体的对象
public class ConcreteComponent implements Component {

    @Override
    public void Operation() {
        System.out.println("对象具体操作");
    }
}

//装饰抽象类继承Component
public abstract class Decorator implements Component {

    protected Component component;

    public void setComponent(Component component) {
        this.component = component;
    }

    @Override
    public void Operation() {
        if (component != null) {
            component.Operation();
        }
    }
}

//装饰的具体实现类
public class ConcreteDecoratorA extends Decorator {

    @Override
    public void Operation() {
        super.Operation();
        System.out.println("具体装饰对象A的操作");
    }
}

public class ConcreteDecoratorB extends Decorator {
    @Override
    public void Operation() {
        super.Operation();
        System.out.println("具体装饰对象B的操作");
    }
}


 public static void main(String[] args) {
        ConcreteComponent component = new ConcreteComponent();
        ConcreteDecoratorA decoratorA = new ConcreteDecoratorA();
        ConcreteDecoratorB decoratorB = new ConcreteDecoratorB();

        //装饰模式:首先用ConcreteComponent实例化对象component,
        //然后用ConcreteDecoratorA的实例化对象decoratorA包装component
        //最后用ConcreteDecoratorB的实例化对象decoratorB包装decoratorA
        decoratorA.setComponent(component);
        decoratorB.setComponent(decoratorA);

        decoratorB.Operation();
    }

【设计模式】——装饰器模式VS代理模式_第2张图片

原理:装饰模式利用 setComponent来对对象进行包装,这样每个装饰对象的实现和如何使用这个对象分离开了。每个装饰对象只关心自己的功能,不需要关心如何被添加到哦对象链中。

代理模式

定义:为其他对象提供一种代理以控制对这个对象的访问。

【设计模式】——装饰器模式VS代理模式_第3张图片

主要解决:在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。

何时使用:想在访问一个类时做一些控制。

如何解决:增加中间层。

关键代码:实现与被代理类组合。

应用实例: 1、Windows 里面的快捷方式。 2、猪八戒去找高翠兰结果是孙悟空变的,可以这样理解:把高翠兰的外貌抽象出来,高翠兰本人和孙悟空都实现了这个接口,猪八戒访问高翠兰的时候看不出来这个是孙悟空,所以说孙悟空是高翠兰代理类。 3、买火车票不一定在火车站买,也可以去代售点。 4、一张支票或银行存单是账户中资金的代理。支票在市场交易中用来代替现金,并提供对签发人账号上资金的控制。 5、spring aop。

优点: 1、职责清晰。 2、高扩展性。 3、智能化。

缺点: 1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。 2、实现代理模式需要额外的工作,有些代理模式的实现非常复杂。

使用场景:按职责来划分,通常有以下使用场景: 1、远程代理。 2、虚拟代理。 3、Copy-on-Write 代理。 4、保护(Protect or Access)代理。 5、Cache代理。 6、防火墙(Firewall)代理。 7、同步化(Synchronization)代理。 8、智能引用(Smart Reference)代理。

实现代码

public interface Subject {
    void request();
}

public class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("真实的请求");
    }
}

public class Proxy implements Subject {

    private Subject realSubject;


    @Override
    public void request() {
        if (realSubject == null) {
            realSubject = new RealSubject();
        }
        realSubject.request();
        System.out.println("代理请求也被执行");
    }
}


public class Demo {
    public static void main(String[] args) {
        Proxy proxy = new Proxy();

        proxy.request();
    }
}

【设计模式】——装饰器模式VS代理模式_第4张图片

装饰器模式和代理模式相同点以及不同点

相同点

两种从设计模式分类来看都属于结构型,因为两者均使用了组合关系。其次两者都能实现对对象方法进行增强处理的效果。

不同点

代理模式,注重对对象某一功能的流程把控和辅助。它可以控制对象做某些事,重心是为了借用对象的功能完成某一流程,而非对象功能如何。

装饰模式,注重对对象功能的扩展,它不关心外界如何调用,只注重对对象功能的加强,装饰后还是对象本身。

举个例子说明两者不同之处,代理和装饰其实从另一个角度更容易去理解两个模式的区别:代理更多的是强调对对象的访问控制,比如说,访问A对象的查询功能时,访问B对象的更新功能时,访问C对象的删除功能时,都需要判断对象是否登陆,那么我需要将判断用户是否登陆的功能抽提出来,并对A对象、B对象和C对象进行代理,使访问它们时都需要去判断用户是否登陆,简单地说就是将某个控制访问权限应用到多个对象上;而装饰器更多的强调给对象加强功能,比如说要给只会唱歌的A对象添加跳舞功能,添加说唱功能等,简单地说就是将多个功能附加在一个对象上。

所以,代理模式注重的是对对象的某一功能的流程把控和辅助,它可以控制对象做某些事,重心是为了借用对象的功能完成某一流程,而非对象功能如何。而装饰模式注重的是对对象功能的扩展,不关心外界如何调用,只注重对对象功能加强,装饰后还是对象本身。 

总结

        装饰器和代理模式均属于结构型模式,两者都是通过组合原对象的方式,实现对原对象功能额外的处理。两者应用点不同就是装饰器处理完整并不改变对象本身,但是代理模式借助对象功能完成某一流程。简单说装饰器模式为了增强功能,而代理模式是为了加以控制。

        题外话,而spring中的FactoryBean的实现更偏向于使用装饰器模式,偏重于对功能进行增强,并未改变对象本身。处理之后从IOC容器中拿到的依旧是自身,而非代理对象。这些内容也会在后续博客 彻底搞懂Factory中继续讲解。      

       漫漫长途,终有回转;余味苦涩,终有回甘——吾辈需继续加油

你可能感兴趣的:(【设计模式】,装饰模式,代理模式)