关于装饰者模式的定义,我就直接引用Head First了:装饰者模式动态的将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案 。 其实装饰者模式的重点在于给对象动态的附加职责,通过对象组合的方式,运行时装饰对象,在不改变任何底层代码的情况下,给现有对象赋予新的职责。 现在我们要为卖煎饼的大妈设计一套系统,让大妈能更好的算账收钱。大妈主要经营煎饼(7元),并可以往其中添加配料烤肠(1元),鸡蛋(1元),如果生意红火,可能会考虑扩大经营其他小吃或添加配料种类。现需要设计出一套系统,以便快速计算出每位顾客所购小吃的价格。 这是一个食品类接口。同样,要符合针对接口编程,不针对实现编程的OO原则。 这是一个配料类接口。配料类接口IDecoratorSnack继承自ISnack接口,因为需要两接口的实现类(装饰者与被装饰对象)具有相同的超类型,只有这样IDecoratorSnack接口才能取代ISnack接口。 这是具体的食品-煎饼类。 食品类(被装饰者)既可以单独使用,也可以被配料类(装饰者)包着使用,因为装饰者和被装饰者对象具有相同的超类型,所以在任何需要原始对象(被包装的)的场合,都可以用装饰过的对象替代它。 如果,我想要一份加鸡蛋和烤肠的煎饼价格是多少?单价类见下: 这是我们的具体配料鸡蛋类。 这是具体的烤肠配料类。 每个装饰者都持有一个被装饰者的对象,这个被装饰者对象不一定是原始对象,也可能是被包装了多层的对象。通过这种组合,加入了新的行为。符合对扩展开放,对修改关闭的OO原则。 我们来收钱吧。我们能够发现,我们能够使用被装饰的对象就像使用原始对象一样,这归功于装饰者与被装饰者具备同样的接口。同样一个原始对象是能够被包装多层的,而在使用者的眼里,它只是一个被赋予了新功能的原始对象而已。 而且扩展起来方便,我们随时加入不同种类小吃和配料类。如我们现在要加一种烤冷面类。 我们再添加一个鸡里脊肉类。 好了,如果用户购买烤冷面+鸡蛋+里脊肉,价格该多少呢? 需要注意的是,通过利用装饰者模式,会造成设计中产生大量的小类,如果过度使用,会使程序变得很复杂。另外可能还会出现类型问题,如果把代码写成依赖于具体的被装饰者类型,不针对抽象接口进行编程,那么就会出现问题。
装饰者模式
public interface ISnack { // 食物的描述 String getDescription(); // 食物的价格 double cost(); }
/** * 这是配料类的接口。 * * <p>装饰者与被装饰者需要具有相同的接口, * 这样用户使用装饰者对象才会和使用原始对象一样。 */ public interface IDecoratorSnack extends ISnack { // 可根据需要扩展属性,如配料大份,小份等 }
public class PancakeSnack implements ISnack { @Override public String getDescription() { return "煎饼"; } @Override public double cost() { return Price.PancakeSnack.price; } }
public enum Price { //鸡蛋、烤肠、煎饼 Egg(1.0), Sausage(1.0), PancakeSnack(7.0); double price; private Price(double price) { this.price = price; } }
public class Egg implements IDecoratorSnack { // 持有被修饰的对象 ISnack iSnack; public Egg(ISnack iSnack) { this.iSnack = iSnack; } @Override public String getDescription() { return iSnack.getDescription() + ",加鸡蛋"; } @Override public double cost() { // 被修饰对象的价格 + 鸡蛋价格 return iSnack.cost() + Price.Egg.price; } }
public class Sausage implements IDecoratorSnack{ //持有被修饰对象的引用 ISnack iSnack; public Sausage(ISnack iSnack) { this.iSnack = iSnack; } @Override public String getDescription() { return iSnack.getDescription() + ",加香肠"; } @Override public double cost() { // 被修饰对象的价格 + 烤肠价格 return iSnack.cost() + Price.Sausage.price; } }
public class DecoratorPatternTest { public static void main(String[] ags) { // 煎饼 + 鸡蛋 + 烤肠 ISnack snackOneISnack = new PancakeSnack(); snackOneISnack = new Egg(snackOneISnack); snackOneISnack = new Sausage(snackOneISnack); // 这样就能够打印出,我们的(煎饼 + 鸡蛋 + 烤肠)价格和描述了 System.out.println(snackOneISnack.getDescription() + "价格:" + snackOneISnack.cost() + "元"); } }
public class ColdRoastSnake implements ISnack{ @Override public String getDescription() { return "烤冷面"; } @Override public double cost() { return Price.ColdRoastSnake.price; } }
public class Chicken implements IDecoratorSnack{ ISnack iSnack; public Chicken(ISnack iSnack) { this.iSnack = iSnack; } @Override public String getDescription() { return iSnack.getDescription() + ",加里脊肉"; } @Override public double cost() { return iSnack.cost() + Price.Chicken.price; } }
public class DecoratorPatternTest { public static void main(String[] ags) { // 烤冷面 + 鸡蛋 + 里脊肉 ISnack snackOneISnack = new ColdRoastSnake(); snackOneISnack = new Egg(snackOneISnack); snackOneISnack = new Chicken(snackOneISnack); // 这样就能够打印出,我们的(烤冷面 + 鸡蛋 + 里脊肉)价格和描述了 System.out.println(snackOneISnack.getDescription() + "价格:" + snackOneISnack.cost() + "元"); } }
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算