定义
在不改变原有对象的基础之上,将功能附加到对象上。提供了比继承更有弹性的替代方案(扩展原有对象功能)
场景
- 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
- 需要动态地给一个对象增加功能,这些功能也可以动态地被撤销。
- 当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。
优点
- 继承的有力补充,比继承灵活,不改变原有对象的情况下给一个对象扩展功能。(继承在扩展功能是静态的,必须在编译时就确定好,而使用装饰者可以在运行时决定,装饰者也建立在继承的基础之上的)
- 通过使用不同装饰类以及这些类的排列组合,可以实现不同的效果。
- 符合开闭原则
缺点
- 会出现更多的代码,更多的类,增加程序的复杂性。
- 动态装饰时,多层装饰时会更复杂。(使用继承来拓展功能会增加类的数量,使用装饰者模式不会像继承那样增加那么多类的数量但是会增加对象的数量,当对象的数量增加到一定的级别时,无疑会大大增加我们代码调试的难度)
涉及对象
- Component(抽象构件):定义需要实现业务的抽象方法。
- ConcreteComponent(具体构件):实现Component接口,用于定义具体的构建对象,可以给它增加额外的职责(方法)。
- Decorator(抽象装饰类):实现Component接口,并创建Component实例对象。用于给具体构件(ConcreteComponent)增加职责。
- ConcreteDecorator(具体装饰类):抽象装饰类的子类,负责向构件添加新的职责。每一个具体装饰类都定义了一些新的行为,它可以调用在抽象装饰类中定义的方法,并可以增加新的方法用以扩充对象的行为
代码实现
饮料抽象类(抽象构件)
/** * 饮料抽象类 * * * @date 2020/4/26 14:20 */ public abstract class BeverageAbstract { String description = "Unknown BeverageAbstract"; public String getDescription() { return description; } /** * cost方法是用来返回饮料的价钱(需在具体类中自己实现) * * @return */ public abstract BigDecimal cost(); }
具体饮料(具体构件也就是具体被装饰类)
/** * 深焙咖啡类(一种具体的饮料) * * @author * @date 2020/4/26 14:21 */ public class DarkRoast extends BeverageAbstract { /** * 说明他是DarkRoast饮料 */ public DarkRoast() { description = "DarkRoast"; } /** * 实现cost方法,用来返回DarkRoast(深焙咖啡)的价格 * * @return */ @Override public BigDecimal cost() { return new BigDecimal("3.00"); } }
/** * 低咖啡因咖啡类(一种具体的饮料) * * @author * @date 2020/4/26 14:24 */ public class Decaf extends BeverageAbstract { /** * 说明他是Decaf饮料 */ public Decaf() { description = "Decaf"; } /** * 实现cost方法,用来返回Decaf(低咖啡因咖啡)的价格 * * @return */ @Override public BigDecimal cost() { return new BigDecimal("4.00"); } }
调料抽象类(抽象装饰类)
/** * 调料抽象类 * * @author * @date 2020/4/26 14:28 */ public abstract class CondimentDecoratorAbstract extends BeverageAbstract{ /** * 所有的调料装饰者都必须重新实现getDescription()方法 * 这样才能够用递归的方式来得到所选饮料的整体描述 * * */ public abstract String getDescription(); }
调料具体类(具体装饰类)
/** * 摩卡调料 * * @author * @date 2020/4/26 15:09 */ public class Mocha extends CondimentDecoratorAbstract { /** * 用一个实例变量记录饮料,也就是被装饰者 */ private BeverageAbstract beverage; /** * 构造器初始化饮料变量 * * @param beverage */ public Mocha(BeverageAbstract beverage) { this.beverage = beverage; } /** * 在原来饮料的基础上添加上Mocha描述(原来的饮料加入Mocha调料,被Mocha调料装饰) * * @return */ @Override public String getDescription() { return beverage.getDescription() + ",Mocha"; } /** * 在原来饮料的基础上加上Mocha的价格(原来的饮料加入Mocha调料,被Mocha调料装饰) * * @return */ @Override public BigDecimal cost() { return new BigDecimal("0.2").add(beverage.cost()); } } /** * 豆浆调料 * * @author * @date 2020/4/26 15:13 */ public class Soy extends CondimentDecoratorAbstract { /** * 用一个实例变量记录饮料,也就是被装饰者 */ private BeverageAbstract beverage; /** * 构造器初始化饮料变量 * * @param beverage */ public Soy(BeverageAbstract beverage) { this.beverage = beverage; } /** * 在原来饮料的基础上添加上Soy描述(原来的饮料加入Soy调料,被Soy调料装饰) * * @return */ @Override public String getDescription() { return beverage.getDescription() + ",Soy"; } /** * 在原来饮料的基础上加上Soy的价格(原来的饮料加入Soy调料,被Soy调料装饰) * * @return */ @Override public BigDecimal cost() { return new BigDecimal("0.3").add(beverage.cost()); } }
测试类
public class Test { public static void main(String[] args) { DarkRoast darkRoast=new DarkRoast(); Mocha mocha=new Mocha(darkRoast); System.out.println("description:"+mocha.getDescription()); System.out.println("cost:"+mocha.cost()); Decaf decaf=new Decaf(); Soy soy=new Soy(decaf); System.out.println("description:"+soy.getDescription()); System.out.println("cost:"+soy.cost()); } }