定义
装饰模式(Decorator Pattern) :动态地给一个对象增加一些额外的职责(Responsibility),就增加对象功能来说,装饰模式比生成子类实现更为灵活。其别名也可以称为包装器(Wrapper),与适配器模式的别名相同,但它们适用于不同的场合。
UML图描述
装饰器模式主要包含四种角色:
1.抽象构件:被修饰类和修饰类的共同父类,如下图的ChafingDish。
2.具体构件:被修饰类的具体实现类,如下图的ClearSoupBase和TomatoSoupBase
3抽象装饰类:修饰类的抽象父类,如下图的Ingredients。
4.具体装饰类:修饰类的具体实现类,如下图的Fungus和FatCattle。
此场景是我们去火锅店吃火锅,火锅是分为汤底和配菜的,我们可以点一个汤底和很多配菜,刚好可以用装饰器模式处理此场景。
代码实现
/** * 火锅顶层抽象 */ public interface ChafingDish { //描述 void description(); }
/** * 配料的抽象父类 */ public abstract class Ingredients implements ChafingDish { protected ChafingDish chafingDish; protected Double price; protected String name; public Ingredients(ChafingDish chafingDish){ this.chafingDish = chafingDish; } @Override public void description() { chafingDish.description(); System.out.println(this.name+"--"+this.price); } }
/** * 配料木耳的具体实现 */ public class Fungus extends Ingredients { public Fungus(ChafingDish chafingDish) { super(chafingDish); this.price = 10.0; this.name = "木耳"; } }
/** * 配料肥牛的具体实现 */ public class FatCattle extends Ingredients{ public FatCattle(ChafingDish chafingDish) { super(chafingDish); this.price = 58.5; this.name = "肥牛"; } }
/** * 清汤火锅的具体实现 */ public class ClearSoupBase implements ChafingDish { @Override public void description() { System.out.println("火锅汤底----清汤火锅"); } }
/** * 番茄汤底火锅的具体实现 */ public class TomatoSoupBase implements ChafingDish { @Override public void description() { System.out.println("火锅汤底----番茄汤底火锅"); } }
/** * 测试类 */ public class Test { public static void main(String[] args) { //汤底 ChafingDish clearSoupBase = new ClearSoupBase(); ChafingDish tomatoSoupBase = new TomatoSoupBase(); //小料 Ingredients fatCattle = new FatCattle(clearSoupBase); Ingredients fungus = new Fungus(tomatoSoupBase); //描述 fatCattle.description(); fungus.description(); } }
适用场景
1.在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
2.需要动态地给一个对象增加功能,这些功能也可以动态地被撤销。
3.当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。不能采用继承的情况主要有两类:第一类是系统中存在大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长;第二类是因为类定义不能继承(如final类)。
装饰器模式的优点
1.装饰模式与继承关系的目的都是要扩展对象的功能,但是装饰模式可以提供比继承更多的灵活性。
2.可以通过一种动态的方式来扩展一个对象的功能,通过配置文件可以在运行时选择不同的装饰器,从而实现不同的行为。
3.通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合。可以使用多个具体装饰类来装饰同一对象,得到功能更为强大的对象。
4.具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合“开闭原则”
装饰器模式的缺点
1.使用装饰模式进行系统设计时将产生很多小对象,这些对象的区别在于它们之间相互连接的方式有所不同,而不是它们的类或者属性值有所不同,同时还将产生很多具体装饰类。这些装饰类和小对象的产生将增加系统的复杂度,加大学习与理解的难度。
2.这种比继承更加灵活机动的特性,也同时意味着装饰模式比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。