设计模式——装饰者模式
创始人
2025-01-08 12:06:08
0

设计模式——装饰者模式

  • 1.问题
    • 1.1 方案一
    • 1.2 方案二
  • 2.装饰者模式
    • 2.1 基本介绍
    • 2.2 结构
    • 2.3 代码实现
  • 3.小结

1.问题

咖啡订单项目:

  1. 咖啡种类/单品咖啡:Espresso(意大利浓咖啡)、ShortBlack、LongBlack(美式咖啡)、Decaf(无因咖啡)
  2. 调料:Milk、Soy(豆浆)、Chocolate
  3. 要求在扩展新的咖啡种类时,具有良好的扩展性、改动方便、维护方便
  4. 使用 OO 的来计算不同种类咖啡的费用:客户可以点单品咖啡,也可以单品咖啡+调料组合。

1.1 方案一

方案一
问题解析:

  1. Drink 是一个抽象类,表示饮料
  2. des 就是对咖啡的描述,比如咖啡的名字
  3. cost()方法就是计算费用,Drink 类中做成一个抽象方法
  4. Decaf 就是单品咖啡, 继承 Drink,并实现 cost
  5. Espress && Milk 就是单品咖啡+调料,这个组合很多,容易产生过多的子类

1.2 方案二

方案二
这里的milk、soy、chocolate都是Boolean类型

问题解析:

  1. 方案2可以控制类的数量,不至于造成很多的类在增加或者删除调料种类时,代码的维护量很大
  2. 考虑到用户可以添加多份 调料时,可以将 hasMilk 返回一个对应 int
  3. 考虑使用 装饰者 模式

2.装饰者模式

2.1 基本介绍

  1. 装饰者模式:动态的将新功能附加到对象上。在对象功能扩展方面,它比继承更有弹性,装饰者模式也体现了开闭原则(ocp)
  2. 这里提到的动态的将新功能附加到对象和 ocp 原则

2.2 结构

装饰(Decorator)模式中的角色:

  • 抽象构件(Component)角色 :定义一个抽象接口以规范准备接收附加责任的对象。
  • 具体构件(Concrete Component)角色 :实现抽象构件,通过装饰角色为其添加一些职责。
  • 抽象装饰(Decorator)角色 : 继承或实现抽象构件,并包含具体构件的实例,可以通过其子
    类扩展具体构件的功能。
  • 具体装饰(ConcreteDecorator)角色 :实现抽象装饰的相关方法,并给具体构件对象添加附
    加的责任。

2.3 代码实现

类图展示:
核心
抽象类Drink:

public abstract class Drink {     private String description;     private double price;      public abstract double cost();      public String getDescription() {         return description;     }      public void setDescription(String description) {         this.description = description;     }      public double getPrice() {         return price;     }      public void setPrice(double price) {         this.price = price;     } } 

装饰者:

public class Decorator extends Drink {      private Drink drink;      public Decorator(Drink drink) {         this.drink = drink;     }      @Override     public double cost() {         return super.getPrice() + drink.cost();     }      @Override     public String getDescription() {         return super.getDescription() + " " + getPrice() + " && " + drink.getDescription();     } } 

Coffee:

public class Coffee extends Drink {      @Override     public double cost() {         return super.getPrice();     } } 

Coffee子类:

public class Decaf extends Coffee {     public Decaf() {         setDescription("无因咖啡");         setPrice(1);     } } public class Espresso extends Coffee {     public Espresso() {         setDescription("意大利咖啡");         setPrice(6);     } } public class LongBlack extends Coffee {     public LongBlack() {         setDescription("longBlack");         setPrice(5);     } } public class ShortBlack extends Coffee {     public ShortBlack() {         setDescription("shortBlack");         setPrice(4);     } } 

装饰器子类:

public class Soy extends Decorator {     public Soy(Drink drink) {         super(drink);         setDescription("豆浆");         setPrice(1.5);     } } public class Milk extends Decorator{     public Milk(Drink drink) {         super(drink);         setDescription("牛奶");         setPrice(2);     } } public class Chocolate extends Decorator {      public Chocolate(Drink drink) {         super(drink);         setDescription("巧克力");         setPrice(3);     } } 

Client调用:

public class Client {     public static void main(String[] args) {         // 两份巧克力+一份牛奶Longblack         Drink order1 = new LongBlack();         System.out.println("order1费用:" + order1.cost());         System.out.println("order1描述:" + order1.getDescription());          order1 = new Milk(order1);         System.out.println("order1加一份牛奶费用:" + order1.cost());         System.out.println("order1加一份牛奶描述:" + order1.getDescription());          order1 = new Chocolate(order1);         System.out.println("order1加一份牛奶,加一份巧克力费用:" + order1.cost());         System.out.println("order1加一份牛奶,加一份巧克力描述:" + order1.getDescription());          order1 = new Chocolate(order1);         System.out.println("order1加一份牛奶,加两份巧克力费用:" + order1.cost());         System.out.println("order1加一份牛奶,加两份巧克力描述:" + order1.getDescription());          System.out.println("==============================");           Drink order2 = new Decaf();         System.out.println("无因咖啡费用:" + order2.cost());         System.out.println("无因咖啡描述:" + order2.getDescription());          order2 = new Milk(order2);         System.out.println("无因咖啡,加一份牛奶费用:" + order2.cost());         System.out.println("无因咖啡,加一份牛奶描述:" + order2.getDescription());     } } 

结果打印:

order1费用:5.0 order1描述:longBlack order1加一份牛奶费用:7.0 order1加一份牛奶描述:牛奶 2.0 && longBlack order1加一份牛奶,加一份巧克力费用:10.0 order1加一份牛奶,加一份巧克力描述:巧克力 3.0 && 牛奶 2.0 && longBlack order1加一份牛奶,加两份巧克力费用:13.0 order1加一份牛奶,加两份巧克力描述:巧克力 3.0 && 巧克力 3.0 && 牛奶 2.0 && longBlack ============================== 无因咖啡费用:1.0 无因咖啡描述:无因咖啡 无因咖啡,加一份牛奶费用:3.0 无因咖啡,加一份牛奶描述:牛奶 2.0 && 无因咖啡 

3.小结

  • 装饰者模式可以带来比继承更加灵活性的扩展功能,使用更加方便,可以通过组合不同的装饰者对象来获取具有不同行为状态的多样化的结果。装饰者模式比继承更具良好的扩展性,完美的遵循开闭原则,继承是静态的附加责任,装饰者则是动态的附加责任。
  • 装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。

相关内容

热门资讯

绝活儿辅助!广西老友玩老是输怎... 绝活儿辅助!广西老友玩老是输怎么办(辅助挂)都是真的有辅助app(讲解有挂)在进入广西老友玩老是输怎...
法门辅助!福建13水插件(辅助... 法门辅助!福建13水插件(辅助挂)一贯是有辅助技巧(有挂技术)1、许多玩家不知道福建13水插件辅助怎...
办法辅助!潮友会app下载官方... 办法辅助!潮友会app下载官方辅助器(辅助挂)真是真的是有辅助app(有挂教程)该软件可以轻松地帮助...
妙招辅助!邯郸胡乐挂辅助(辅助... 妙招辅助!邯郸胡乐挂辅助(辅助挂)好像存在有辅助插件(有挂方略)1、上手简单,内置详细流程视频教学,...
教程书辅助!乐酷辅助(辅助挂)... 教程书辅助!乐酷辅助(辅助挂)其实存在有辅助脚本(有挂细节)乐酷辅助能透视中分为三种模型:乐酷辅助模...
学习辅助!决战卡五星辅助(辅助... 学习辅助!决战卡五星辅助(辅助挂)本来真的是有辅助软件(有人有挂)学习辅助!决战卡五星辅助(辅助挂)...
绝活辅助!边锋嘉兴麻将辅助器(... 绝活辅助!边锋嘉兴麻将辅助器(辅助挂)真是真的有辅助神器(新版有挂)1、边锋嘉兴麻将辅助器公共底牌简...
举措辅助!枫叶辅助器(辅助挂)... 举措辅助!枫叶辅助器(辅助挂)本来存在有辅助技巧(竟然有挂)1、下载好枫叶辅助器正确养号方法之后点击...
讲义辅助!点我达辅助(辅助挂)... 讲义辅助!点我达辅助(辅助挂)一直存在有辅助技巧(有人有挂)1、点我达辅助辅助器安装包、点我达辅助辅...
模块辅助!威信茶馆有挂的吗(辅... 模块辅助!威信茶馆有挂的吗(辅助挂)一直真的是有辅助脚本(揭秘有挂)1、玩家可以在威信茶馆有挂的吗线...