51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

Java 设计模式之装饰模式(八)

一、前言 {#一、前言}

本篇主题为结构型模式中的第三个模式--装饰模式。上篇 Java 设计模式主题为 《Java 设计模式之桥接模式(七)》

二、简单介绍 {#二、简单介绍}

2.1 定义 {#2.1-定义}

装饰(Decorator)模式又叫做包装模式,其功能是动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生成子类更为灵活,是继承关系的一个替换方案。

2.2 参与角色 {#2.2-参与角色}

  1. Component:定义一个对象接口,可以给这些对象动态地添加职责。

  2. ConcreteComponent:定义一个对象,可以给这个对象添加一些职责。

  3. Decorator:维持一个指向 Component 对象的指针,并定义一个与 Component 接口一致的接口。

  4. ConcreteDecorator:向组件添加职责。

2.3 应用场景 {#2.3-应用场景}

  1. 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。

  2. 当不能采用生成子类的方法进行扩充时。

三、实现方式 {#三、实现方式}

我们以人的打扮为例。人打扮需要穿衣,穿裤,穿鞋子。代码表示如下:

Person 类:

|------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | public class Person { private String name; public Person(String name) { this.name = name; } public void putOnClothes() { System.out.println(this.name + "穿衣服"); } public void putOnTrousers() { System.out.println(this.name + "穿裤子"); } public void putOnShoes() { System.out.println(this.name + "穿鞋子"); } } |

客户端:

|---------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 | public class Client { public static void main(String[] args) { Person person = new Person("小白"); person.putOnClothes(); person.putOnTrousers(); person.putOnShoes(); } } |

打印:

|---------------|---------------------------| | 1 2 3 | 小白穿衣服 小白穿裤子 小白穿鞋子 |

上述代码很简单,但是扩展性不好。当我们需要添加打领带、戴手表的行为时,需要修改 Person 类,违背了开放封闭原则。

因此,我们需要将人和打扮的行为抽离出来:

Person 类:

|---------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 | public class Person { private String name; public Person(String name) { this.name = name; } public String getName() { return name; } } |

打扮类:

|------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | public abstract class DressUp { public abstract void dressup(Person person); } class ClothesDressUp extends DressUp { @Override public void dressup(Person person) { System.out.println(person.getName() + "穿衣服"); } } class TrousersDressUp extends DressUp { @Override public void dressup(Person person) { System.out.println(person.getName() + "穿裤子"); } } class ShoesDressUp extends DressUp { @Override public void dressup(Person person) { System.out.println(person.getName() + "穿鞋子"); } } |

客户端:

|---------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public class Client { public static void main(String[] args) { Person person = new Person("小白"); DressUp du1 = new ClothesDressUp(); du1.dressup(person); DressUp du2 = new TrousersDressUp(); du2.dressup(person); DressUp du3 = new ShoesDressUp(); du3.dressup(person); } } |

执行结果与上文的一致。现在,当我们添加新的打扮行为时,只需新增 DressUp 的子类即可。

但是,上边的代码没有封装性,每打扮一次都要调用 dressup 方法一次,就感觉人是光着身在公共场合进行打扮穿衣、穿鞋。因此,我们需要一种模式将这些打扮的细节封装起来,就像建造者模式一样。

不过,此次的需求不能使用建造者模式。因为建造者模式封装过程/细节是一个固定的顺序/模式,而当前需求是人的打扮,打扮的行为是多种多样的,如:穿衣穿裤、穿衣打领带、穿鞋戴手表等。

这样就引出了本章的主题--装饰模式:

Person 接口与实现类(Component 和 ConcreteComponent):

|---------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 | public interface Person { public void decorate(); } class Man implements Person { @Override public void decorate() { System.out.println("男人打扮"); } } |

装饰类(Decorator 和 ConcreteDecorator):

|------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | public class Decorator implements Person { private Person person; public Decorator(Person person) { this.person = person; } @Override public void decorate() { this.person.decorate(); } } class ClothesDecorator extends Decorator { public ClothesDecorator(Person person) { super(person); } public void decorate() { super.decorate(); System.out.println("穿衣服"); } } class TrousersDecorator extends Decorator { public TrousersDecorator(Person person) { super(person); } public void decorate() { super.decorate(); System.out.println("穿裤子"); } } class ShoesDecorator extends Decorator { public ShoesDecorator(Person person) { super(person); } public void decorate() { super.decorate(); System.out.println("穿鞋子"); } } |

客户端:

|---------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | public class Client { public static void main(String[] args) { Person person = new Man(); Person decorator = new Decorator(person); System.out.println("======第一种打扮======="); ClothesDecorator cd = new ClothesDecorator(decorator); TrousersDecorator td = new TrousersDecorator(cd); td.decorate(); System.out.println("======第二种打扮======="); ShoesDecorator sd = new ShoesDecorator(person); sd.decorate(); } } |

打印:

|-----------------------|---------------------------------------------------------------------| | 1 2 3 4 5 6 7 | ======第一种打扮======= 男人打扮 穿衣服 穿裤子 ======第二种打扮======= 男人打扮 穿鞋子 |

总结:装饰模式有效地把类的核心职责和装饰功能区分开来,而且去除了相关类的重复的装饰逻辑。

UML 类图表示如下:

赞(2)
未经允许不得转载:工具盒子 » Java 设计模式之装饰模式(八)