设计模式第四篇,装饰者模式,大家多多指教。
简介
装饰者模式是动态的将责任附加到对象上(引自《Head First设计模式》)。这里的重点在于动态这两个字,我们都知道继承的实现的方式,它是是类编译的时候就去加载文件,属于一种静态的附加,而我们要实现动态的附加就不能单纯的通过继承来实现。在这种背景下,装饰者模式就应运而生了。装饰者模式的实现:首先所有的类都有一个共同的抽象,这个抽象可以是一个抽象类,也可以是一个接口,所有的类该抽象的子类或者实现。语言描述比较抽象,下面我们通过一个例子来描述该模式。
例子
我们举一个吃火锅的例子,根据装饰者模式的特点:
首先我们要有个共同的抽象,这里我们通过接口来实现,这个接口我们称之为锅底。
/* * 锅底 */ public interface Hotpot { /** 描述 */ String getName(); /** 价格 */ Double getPrice(); }
第二步,我们设计具体的锅底类,我们分为酱香锅、香辣锅和清汤锅,这是底锅,每笔单都必须有且只有一个。
public class JamHotpot implements Hotpot{ @Override public String getName() { return "酱香锅"; } @Override public Double getPrice() { return 4.0; } } public class SpicyHotpot implements Hotpot{ @Override public String getName() { return "香辣锅"; } @Override public Double getPrice() { return 4.0; } } public class ClearSoupHotpot implements Hotpot{ @Override public String getName() { return "清汤锅"; } @Override public Double getPrice() { return 3.0; } }
第三步,我们新增一个配菜接口,继承共同的接口锅底,这个接口用来作为所有配菜的父级,该接口可以拓展所以配菜的共有属性
/* * 配菜 */ public interface SideDish extends Hotpot { //可拓展配菜的公共属性 }
第四步,我们需要新增具体的配菜类,这里的配菜类我们注意到比锅底类多了成员变量和构造方法,而且getName和getPrice方法多了加了传入参数,这个就是为了动态的去附加功能,具体怎么实现参考最后一步。
/* * 牛肉 */ public class Beef implements SideDish { private Hotpot hotpot; public Beef(Hotpot hotpot) { this.hotpot = hotpot; } @Override public String getName() { return hotpot.getName() + ",牛肉"; } @Override public Double getPrice() { return hotpot.getPrice() + 38.0; } } /* * 生菜 */ public class Lettuce implements SideDish { private Hotpot hotpot; public Lettuce(Hotpot hotpot) { this.hotpot = hotpot; } @Override public String getName() { return hotpot.getName() + ",生菜"; } @Override public Double getPrice() { return hotpot.getPrice() + 8.0; } }
最后我们测试:
public class DecoratorTest { public static void main(String[] args) { System.out.println("=======酱香锅底加牛肉"); Hotpot hotpot = new JamHotpot(); hotpot = new Beef(hotpot); hotpot = new Lettuce(hotpot); System.out.println("===火锅的价格为:" + hotpot.getPrice() + "元"); //如果我们需要更多的配菜参考上面的方式去添加更多的配菜 } }
总结
如上面所描写的那样,我只需要前台传递给我们所点的锅底和配菜,我们后台去动态的生成一个新的火锅对象。这么设计的好处的拓展极其方便,就算这个火锅店加了新的锅底,或者是配菜,对我们之前的代码是没有任何影响的,这就是所谓的开闭原则(对拓展开放,对修改关闭),后面我们会讲到设计模式相应的原则。除了上面的好处之外,装饰者模式也有他本身不能忽视的问题,那就是每次生成一笔订单都会生成很多小对象,如果该笔单对象很多的话,对我们的内存是个不小的考验,而且过多的小类会让我们的系统变得很复杂,让人很难以理解。所以装饰器模式有利有弊(更多的是利大于弊),我们可以好好思考装饰者模式应用场景,然后进一步掌握这种设计思想。
番外
想了解装饰者模式的更多详细信息可以通过jdk源码或者spring源码去了解。jdk中IO操作就有通过装饰者模式实现的,FilterInputStream和它的实现就是一个装饰者模式,同样的在spring源码中,凡事以Decorator结尾的类都是实现的装饰者模式,当然不是所有的装饰器模式都是以Decorator结尾的。
原文地址:https://www.cnblogs.com/blue-and-white/p/11078991.html