-
给类或对象添加行为的方式
- 使用继承,这是一个静态的方式,在编译的时候就已经决定了子类的行为,不便于空值增加子类行为的方式和时机。
- 适用关联,将一个对象嵌入到另一个对象中,这是一种动态的方式,可以在应用程序中动态的控制。
-
装饰者模式在不改变原类文件和继承(与适配器模式的小的区别)的情况下,动态的扩展一个对象的功能。
-
装饰者模式通过创建一个包装对象(装饰对象)包裹真实的对象。
-
适配器模式与装饰者模式的区别
- 适配器模式是讲一个接口转变成另一个接口(兼容性),通过改变原有的接口达到重复使用的目的。
- 适配器模式是在不改变原有接口的情况下,增强原有对象的功能;或者在不改变原有对象的处理方法而提升性能(动态的添加行为)。
-
装饰者模式的UML图
-
component抽象构建(最终想要得到的对象),concreteComponent具体的对象,decorator抽象装饰类,concreteDecorator具体装饰类,起到该Conponent添加职责的功能。
-
装饰者模式的代码实现过程
-
创建一个抽象原型接口
/** * Component对象(抽象对象类),手类抓饼接口,用来被装饰 */ public interface Cake { String nameDetail(); Double price(); }
-
创建一个具体的原型类
/** * 基础对象类(原型对象),原味手抓饼 */ public class CakeImpl implements Cake { @Override public String nameDetail() { return "手抓饼"; } @Override public Double price() { return 5.00; } }
-
创建原型类的装饰者抽象类
/** * 装饰者抽象类,手抓饼的装饰类,第一次使用了构造方法 */ public class CakeDecorator implements Cake { private Cake cake; /** * 构造函数是为了能堆上一步的对象进行处理 * @param cake */ public CakeDecorator(Cake cake) { this.cake = cake; } @Override public String nameDetail() { return cake.nameDetail(); } @Override public Double price() { return cake.price(); } }
-
创建三个原型抽象类的具体装饰类
/** * 具体的装饰者类,鸡蛋手抓饼 * 1. 继承了父类的构造方法 * 2. 实现了具体的装饰装饰内容 */ public class AggCakeDecorator extends CakeDecorator { public AggCakeDecorator(Cake cake) { super(cake); } /** * 实现具体的装饰内容 * @return */ @Override public String nameDetail() { return "鸡蛋"+super.nameDetail(); } @Override public Double price() { return super.price()+1.5; } }
/** * 具体的装饰者类,牛肉手抓饼 * 1. 继承了父类的构造方法 * 2. 实现了具体的装饰装饰内容 */ public class MeatCakeDecorator extends CakeDecorator { public MeatCakeDecorator(Cake cake) { super(cake); } @Override public String nameDetail() { return "牛肉"+super.nameDetail(); } @Override public Double price() { return super.price()+2; } }
/** * 具体的装饰者类,奶油手抓饼 * 1. 继承了父类的构造方法 * 2. 实现了具体的装饰装饰内容 */ public class MilkCakeDecorator extends CakeDecorator { public MilkCakeDecorator(Cake cake) { super(cake); } @Override public String nameDetail() { return "奶油"+super.nameDetail(); } @Override public Double price() { return super.price()+3; } }
-
编写测试类
public class Test { public static void main(String[] args) { Cake cake = new CakeImpl(); System.out.println("name: " + cake.nameDetail() +", price: " + cake.price()); System.out.println("--------------------"); Cake cake1 = new AggCakeDecorator(cake); System.out.println("name: " + cake1.nameDetail() +", price: " + cake1.price()); System.out.println("--------------------"); Cake cake2 = new MeatCakeDecorator(cake1); System.out.println("name: " + cake2.nameDetail() +", price: " + cake2.price()); System.out.println("--------------------"); /** * 标识了制作顺序与流程,在生产中要进行流水线制作程序的时候, 有可能会严格的把控制作流程 * 装饰者模式不仅完成了操作细节的装饰,还能堆操作的流程提供很好的调用方式 */ Cake cake3 = new MilkCakeDecorator(cake2); System.out.println("name: " + cake3.nameDetail() +", price: " + cake3.price()); } }
-
-
装饰者模式的优点
- 装饰者模式可以提供比继承更多的灵活性
- 可以通过一种动态的方式来扩展一个对象的功能,在运行时选择不同的装饰器,实现不同的行为
- 通过使用不同具体的装饰器,以及这些装饰器的排列组合,可以创造出很多不同行为的组合。实现多个具体的装饰类装饰同一个对象,得到功能更为强大的对象。
- 具体的构造类与具体的装饰类可以独立变化,用户可以根据需要增加新的具体构建类和具体装饰类;使用的时候还可以进行组合,原有的代码无需改变,符合"开闭原则"
-
装饰者模式的缺点
- 会产生很多小对象,增加系统的复杂度
- 这种比继承更加领过机动的特性,同时也意味着装饰模式比继承更加容易出错,排错也很困难,对于多次装饰的对象,调试的时候寻找错误需要逐级排查,比较繁琐
-
装饰者模式的使用场景
- 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责
- 需要动态的给一个对象增加功能,这些功能也可以动态的撤销,当不能采用继承的方式对系统进行扩展或者采用继承不利于系统扩展和维护的时候。
-
装饰者模式在JDK中的使用