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

柔光的暖阳◎ 2023-02-17 14:57 63阅读 0赞

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

装饰器模式

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

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ppYWRhamluZzI2Nw_size_16_color_FFFFFF_t_70

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

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

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

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

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

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

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

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

注意事项:可代替继承。

实现代码

  1. //充当抽象角色,不应该具体实现
  2. public interface Component {
  3. void Operation();
  4. }
  5. //有一个具体的对象
  6. public class ConcreteComponent implements Component {
  7. @Override
  8. public void Operation() {
  9. System.out.println("对象具体操作");
  10. }
  11. }
  12. //装饰抽象类继承Component
  13. public abstract class Decorator implements Component {
  14. protected Component component;
  15. public void setComponent(Component component) {
  16. this.component = component;
  17. }
  18. @Override
  19. public void Operation() {
  20. if (component != null) {
  21. component.Operation();
  22. }
  23. }
  24. }
  25. //装饰的具体实现类
  26. public class ConcreteDecoratorA extends Decorator {
  27. @Override
  28. public void Operation() {
  29. super.Operation();
  30. System.out.println("具体装饰对象A的操作");
  31. }
  32. }
  33. public class ConcreteDecoratorB extends Decorator {
  34. @Override
  35. public void Operation() {
  36. super.Operation();
  37. System.out.println("具体装饰对象B的操作");
  38. }
  39. }
  40. public static void main(String[] args) {
  41. ConcreteComponent component = new ConcreteComponent();
  42. ConcreteDecoratorA decoratorA = new ConcreteDecoratorA();
  43. ConcreteDecoratorB decoratorB = new ConcreteDecoratorB();
  44. //装饰模式:首先用ConcreteComponent实例化对象component,
  45. //然后用ConcreteDecoratorA的实例化对象decoratorA包装component
  46. //最后用ConcreteDecoratorB的实例化对象decoratorB包装decoratorA
  47. decoratorA.setComponent(component);
  48. decoratorB.setComponent(decoratorA);
  49. decoratorB.Operation();
  50. }

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ppYWRhamluZzI2Nw_size_16_color_FFFFFF_t_70 1

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

代理模式

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

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ppYWRhamluZzI2Nw_size_16_color_FFFFFF_t_70 2

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

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

如何解决:增加中间层。

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

应用实例: 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)代理。

实现代码

  1. public interface Subject {
  2. void request();
  3. }
  4. public class RealSubject implements Subject {
  5. @Override
  6. public void request() {
  7. System.out.println("真实的请求");
  8. }
  9. }
  10. public class Proxy implements Subject {
  11. private Subject realSubject;
  12. @Override
  13. public void request() {
  14. if (realSubject == null) {
  15. realSubject = new RealSubject();
  16. }
  17. realSubject.request();
  18. System.out.println("代理请求也被执行");
  19. }
  20. }
  21. public class Demo {
  22. public static void main(String[] args) {
  23. Proxy proxy = new Proxy();
  24. proxy.request();
  25. }
  26. }

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ppYWRhamluZzI2Nw_size_16_color_FFFFFF_t_70 3

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

相同点

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

不同点

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

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

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

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

总结

  1. 装饰器和代理模式均属于结构型模式,两者都是通过组合原对象的方式,实现对原对象功能额外的处理。两者应用点不同就是装饰器处理完整并不改变对象本身,但是代理模式借助对象功能完成某一流程。简单说装饰器模式为了增强功能,而代理模式是为了加以控制。
  2. 题外话,而spring中的FactoryBean的实现更偏向于使用装饰器模式,偏重于对功能进行增强,并未改变对象本身。处理之后从IOC容器中拿到的依旧是自身,而非代理对象。这些内容也会在后续博客 彻底搞懂Factory中继续讲解。

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

发表评论

表情:
评论列表 (有 0 条评论,63人围观)

还没有评论,来说两句吧...

相关阅读

    相关 设计模式-装饰模式

    > 装饰器模式也称为包装模式是指在不改变原有对象的基础上,将功能附加到对象上,提供比继承更有弹性的替代方案(扩展原有对象的功能),属于结构型模式 装饰器模式的核心是功能扩展,

    相关 设计模式——装饰模式

    > 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。 >

    相关 设计模式-装饰模式

    装饰器模式 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个

    相关 设计模式----装饰模式

           今天来学习分析下装饰器模式,首先我们分析它的名字应该要知道这个模式的作用应该就是类似我们用装饰品一样,随用随取的特点。发挥你的想象,如果我们写的程序能有这样的特点