设计模式轻松学【十一】装饰模式

简介: 如果要扩展一些功能,我们可以采用装饰模式来实现。装饰者模式以对客户透明的方式动态地给一个对象附加上更多的责任。换言之,客户端并不会觉得对象在装饰前和装饰后有什么不同。装饰者模式可以在不使用创造更多子类的情况下,将对象的功能加以扩展。

定义与特点

  • 定义

    装饰者模式动态地将责任附加到对象身上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。

  • 详细概述

    装饰者模式又名包装(Wrapper)模式,是一种对象结构型模式。是一种用于替代继承的技术,它通过一种无须定义子类的方式来给对象动态增加职责,使用对象之间的关联关系取代类之间的继承关系。

  • 参与角色

    • 抽象构件(Component):具体构件和抽象装饰类的共同父类,声明了在具体构件中实现的业务方法。
    • 具体构件(ConcreteComponent):实现了抽象构件中声明的方法,装饰器可以给它增加额外的职责(方法)。
    • 抽象装饰(Decorator):继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
    • 具体装饰(ConcreteDecorator):抽象装饰类的子类,负责向具体构件添加新的职责。每一个具体装饰类都定义了一些新的行为,它可以调用在抽象装饰类中定义的方法,并可以增加新的方法用以扩充对象的行为。
  • 类结构图

    image.png

  • 结构代码分析

    • 定义抽象构件

      interface Component{
          public void operation();
      }
    • 具体构件

      class ConcreteComponent implements Component{
          public ConcreteComponent(){
              System.out.println("创建具体构件角色");       
          }   
          public void operation(){
              System.out.println("调用具体构件角色的方法operation()");           
          }
      }
    • 抽象装饰类

      class Decorator implements Component{
      
          private Component component;
          
          public Decorator(Component component){
              this.component = component;
          }
          
          public void operation(){
              component.operation();
          }
      }
    • 具体装饰类

      //具体装饰角色
      class ConcreteDecorator extends Decorator{
      
          public ConcreteDecorator(Component component){
              super(component);
          }   
          
          public void operation(){
              super.operation();
              addedFunction();
          }
          
          public void addedFunction(){
              System.out.println("为具体构件角色增加额外的功能addedFunction()");           
          }
      }
    • 客户端调用

      public class DecoratorPattern{
          public static void main(String[] args){
              Component p = new ConcreteComponent();
              p.operation();
              
              System.out.println("---------------------------------");
              
              Component d = new ConcreteDecorator(p);
              d.operation();
          }
      }
      
      //运行结果
      创建具体构件角色
      调用具体构件角色的方法operation()
      ---------------------------------
      调用具体构件角色的方法operation()
      为具体构件角色增加额外的功能addedFunction()

模式实现分析

清楚了装饰模式的结构组成后,我们来做一个小小的手抓饼案例。我们知道,手抓饼主要靠配料挣钱,比如加黄瓜、煎蛋、火腿之类的,每个配料不一样价格也不一样。

image.png

这个手抓饼加配料的过程,我们采用装饰模式来解决,主体是手抓饼和肉夹馍,而配料则是装饰者,我先用UML类图来描述一下类之间的协作关系。

image.png

  • 抽象构件

    public abstract class Pancake {
        
        public String desc = "抽象饼";
    
        public String getDesc() {
            return desc;
        }
        
        public abstract double price();
    
    }
  • 具体构件

    public class Roujiamo extends Pancake {
        public Roujiamo() {
            desc = "肉夹馍";
        }
    
        @Override
        public double price() {
            return 6;
        }
    }
  • 抽象装饰类

    public abstract class Condiment extends Pancake {
        public abstract String getDesc();
    }
  • 具体装饰类

    //煎蛋
    public class FiredEgg extends Condiment {
        private Pancake pancake;
        
        public FiredEgg(Pancake pancake) {
            this.pancake = pancake;
        }
    
        @Override
        public String getDesc() {
            return pancake.getDesc() + ", 煎蛋";
        }
    
        @Override
        public double price() {
            return pancake.price() + 2;
        }
    }
    
    //火腿
    public class Ham extends Condiment {
        private Pancake pancake;
        
        public Ham(Pancake pancake) {
            this.pancake = pancake;
        }
    
        @Override
        public String getDesc() {
            return pancake.getDesc() + ", 火腿";
        }
    
        @Override
        public double price() {
            return pancake.price() + 1.5;
        }
    }
  • 客户端调用程序

    public class MyTest {
        
        @Test
        public void test() {
            Pancake roujiamo = new Roujiamo();
            roujiamo = new FiredEgg(roujiamo);
            roujiamo = new FiredEgg(roujiamo);
            roujiamo = new Ham(roujiamo);
            roujiamo = new MeatFloss(roujiamo);
            roujiamo = new Cucumber(roujiamo);
            //我好饿
            System.out.println(String.format("%s ¥%s", roujiamo.getDesc(), roujiamo.price()));
        }
    
    }

由于具体构件类和装饰类都实现了相同的抽象构件接口,因此装饰模式以对客户透明的方式动态地给一个对象附加上更多的责任,换言之,客户端并不会觉得对象在装饰前和装饰后有什么不同。

譬如我们给肉夹馍加上一个鸡蛋可以这么写 roujiamo = new FiredEgg(roujiamo);,客户端仍然可以把 roujiamo 当成原来的 roujiamo一样,不过现在的 roujiamo已经被装饰加上了鸡蛋

总结

  • 优点

    (1)装饰模式与继承关系的目的都是要扩展对象的功能,但是装饰模式可以提供比继承更多的灵活性。装饰模式允许系统动态决定“贴上”一个需要的“装饰”,或者除掉一个不需要的“装饰”。继承关系则不同,继承关系是静态的,它在系统运行前就决定了。

    (2)通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合。

  • 缺点

    由于使用装饰模式,可以比使用继承关系需要较少数目的类。使用较少的类,当然使设计比较易于进行。但是,在另一方面,使用装饰模式会产生比使用继承关系更多的对象。更多的对象会使得查错变得困难,特别是这些对象看上去都很相像。

JDK中的应用

装饰者模式在Java语言中的最著名的应用莫过于Java I/O标准库的设计了。

image.png

根据上图可以看出:

  • 抽象构件(Component)角色:InputStream,OutputStream,Reader,Writer,为各种子类型提供统一的接口。
  • 具体构件(ConcreteComponent)角色:由ByteArrayInputStream、FileInputStream、PipedInputStream、StringBufferInputStream等类扮演。它们实现了抽象构件角色所规定的接口。
  • 抽象装饰(Decorator)角色:FilterInputStream,FilterOutputStream。它实现了InputStream所规定的接口。
  • 具体装饰(ConcreteDecorator)角色:由几个类扮演,分别是BufferedInputStream、DataInputStream以及两个不常用到的类LineNumberInputStream、PushbackInputStream。
目录
相关文章
|
6月前
|
设计模式 PHP
php设计模式--装饰模式(七)装饰模式完成文章编辑
php设计模式--装饰模式(七)装饰模式完成文章编辑
38 0
|
6月前
|
设计模式 中间件 PHP
设计模式 | 装饰模式
设计模式 | 装饰模式
33 0
|
设计模式
设计模式系列教程(12) - 装饰模式
设计模式系列教程(12) - 装饰模式
35 0
|
设计模式 算法 uml
结构型设计模式01-装饰模式
结构型设计模式01-装饰模式
31 0
|
设计模式
设计模式13 - 装饰模式【Decorator Pattern】
设计模式13 - 装饰模式【Decorator Pattern】
28 0
|
3月前
|
设计模式 Java
【八】设计模式~~~结构型模式~~~装饰模式(Java)
文章详细介绍了装饰模式(Decorator Pattern),这是一种对象结构型模式,用于在不使用继承的情况下动态地给对象添加额外的职责。装饰模式通过关联机制,使用装饰器类来包装原有对象,并在运行时通过组合的方式扩展对象的行为。文章通过图形界面构件库的设计案例,展示了装饰模式的动机、定义、结构、优点、缺点以及适用场景,并提供了Java代码实现和应用示例。装饰模式提高了系统的灵活性和可扩展性,适用于需要动态、透明地扩展对象功能的情况。
【八】设计模式~~~结构型模式~~~装饰模式(Java)
|
5月前
|
设计模式
结构型设计模式之装饰模式
结构型设计模式之装饰模式
|
6月前
|
设计模式 JavaScript Java
[设计模式Java实现附plantuml源码~结构型] 扩展系统功能——装饰模式
[设计模式Java实现附plantuml源码~结构型] 扩展系统功能——装饰模式
|
6月前
|
设计模式 Go
[设计模式 Go实现] 结构型~装饰模式
[设计模式 Go实现] 结构型~装饰模式
|
设计模式
设计模式——装饰模式
设计模式——装饰模式
58 0

热门文章

最新文章

  • 1
    C++一分钟之-设计模式:工厂模式与抽象工厂
    43
  • 2
    《手把手教你》系列基础篇(九十四)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-下篇(详解教程)
    49
  • 3
    C++一分钟之-C++中的设计模式:单例模式
    58
  • 4
    《手把手教你》系列基础篇(九十三)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-上篇(详解教程)
    38
  • 5
    《手把手教你》系列基础篇(九十二)-java+ selenium自动化测试-框架设计基础-POM设计模式简介(详解教程)
    63
  • 6
    Java面试题:结合设计模式与并发工具包实现高效缓存;多线程与内存管理优化实践;并发框架与设计模式在复杂系统中的应用
    58
  • 7
    Java面试题:设计模式在并发编程中的创新应用,Java内存管理与多线程工具类的综合应用,Java并发工具包与并发框架的创新应用
    42
  • 8
    Java面试题:如何使用设计模式优化多线程环境下的资源管理?Java内存模型与并发工具类的协同工作,描述ForkJoinPool的工作机制,并解释其在并行计算中的优势。如何根据任务特性调整线程池参数
    50
  • 9
    Java面试题:请列举三种常用的设计模式,并分别给出在Java中的应用场景?请分析Java内存管理中的主要问题,并提出相应的优化策略?请简述Java多线程编程中的常见问题,并给出解决方案
    110
  • 10
    Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
    78
  • 下一篇
    无影云桌面