zoukankan      html  css  js  c++  java
  • 3.Decorator Pattern(装饰者模式)

    装饰者模式:

      动态地将责任附加到对象上。想要扩展功能,装饰者提供有别于继承的另一种选择。

    举例:

      不知道大家学校的食堂是什么点餐制度(或者大家就直接想成吃火锅,我们要火锅料 + 配菜),我们学校的点餐是:主食大米 + 你想要吃的菜(每个菜都装在小碗中)。现在问题来了,我点的是大米(0.8元) + 红烧茄子(2.0元) + 荔枝肉(3.5元) + 一个鸡腿(3.5元) + 炒土豆(1.0元),一共10.8元。

      这只是我想要吃的食品,每个同学点餐都不一样,所以价格会随着所点食物的不同而不同。还有一点就是我们点餐都要点米饭(这是规定,没有那么多理由,就是这么任性。其实不然,我们需要有个主对象去修饰),那么我们应该怎样实现这样的点餐计价方式呢?

    生活中的实例:

      有一家咖啡店,它提供给我们如下代码:

    1 public abstract class Beverage{//饮料抽象类
    2     String description = "Unknown Beverage";//饮料名称
    3     
    4     public String getDescription(){//获取饮料名称的方法
    5         return description;
    6     }
    7     
    8     public abstract double cost();//饮料价格
    9 }
    Beverage

      这家咖啡店有主饮料(相当于米饭):Espresso(浓缩咖啡1.99$)、HouseBlend(综合咖啡0.89$)、DarkRoast(深焙0.99$)、Decaf(低咖啡因1.05$)四种

      还有各种配料:Milk(牛奶0.10$)、Mocha(摩卡0.20$)、Soy(豆浆0.15$)、Whip(奶泡0.10$)四种

      咖啡店想要做出一个点饮料机器,可以点一种主饮料再从四种配料中任意选1到4中配料。该机器可以算出最后的总价,并且可以显示都点了那些东西。

    分析:

      主饮料全部继承自Beverage抽象类,因为店家已经给了Beverage抽象类,我们只能采用继承方式来实现四种主饮料类,如果没有给建议使用接口方式实现(多用组合,少用继承。)

    主饮料我们只实现其中两种:

     1 public class Espresso extends Beverage{//浓缩咖啡类
     2     
     3     public Espresso(){
     4         description = "Espresso";
     5     }
     6     
     7     public double cost(){
     8         return 1.99;
     9     }
    10 }
    Espresso
    1 public class HouseBlend extends Beverage{//综合咖啡类
    2     public HouseBlend(){
    3         description = "House Blend Coffee";
    4     }
    5     
    6     public double cost(){
    7         return .89;
    8     }
    9 }
    HouseBlend

    配料也继承自Beverage,不过我们在中间加一个桥梁,将主饮料和配料区别对待,这样对于以后的修改有好处:

    1 public abstract class CondimentDecorator extends Beverage{//配料接口
    2     public abstract String getDescription();
    3 }
    CondimentDecorator

      所有配料都继承自上面的CondimentDecorator接口:

    配料我们实现其中三种:

     1 public class Mocha extends CondimentDecorator {//配料:摩卡类
     2     Beverage beverage;//每个配料中都有一个Beverage对象,该对象存储的是配料修饰的产品。
     3                       //关键就在这个对象,最后结算的时候,我们可以调用该对象的getDescription和cost方法
     4                       //我称它为盒子里面套盒子
     5     
     6     public Mocha(Beverage beverage){
     7         this.beverage = beverage;
     8     }
     9     
    10     public String getDescription(){
    11         return beverage.getDescription() + ", Mocha";//调用beverage对象的getDescription()方法
    12     }
    13     
    14     public double cost(){
    15         return .20 + beverage.cost();//调用beverage对象的cost()方法
    16     }
    17 }
    Mocha
     1 public class Soy extends CondimentDecorator {
     2     Beverage beverage;
     3     
     4     public Soy(Beverage beverage){
     5         this.beverage = beverage;
     6     }
     7     
     8     public String getDescription(){
     9         return beverage.getDescription() + ", Soy";
    10     }
    11     
    12     public double cost(){
    13         return .15 + beverage.cost();
    14     }
    15 }
    Soy
     1 public class Whip extends CondimentDecorator {
     2     Beverage beverage;
     3     
     4     public Whip(Beverage beverage){
     5         this.beverage = beverage;
     6     }
     7     
     8     public String getDescription(){
     9         return beverage.getDescription() + ", Whip";
    10     }
    11     
    12     public double cost(){
    13         return .10 + beverage.cost();
    14     }
    15 }
    Whip

      测试类:

     1 public class StarbuzzCoffee{
     2     
     3     public static void main(String args[]){
     4         Beverage beverage = new Espresso();//只点主饮料:Espresso
     5         System.out.println(beverage.getDescription() + " $" + beverage.cost());
     6         
     7         Beverage beverage2 = new HouseBlend();//点主饮料:HouseBlend
     8         beverage2 = new Mocha(beverage2);//在主饮料中加入Mocha配料:HouseBlend + Mocha
     9         beverage2 = new Soy(beverage2);//在饮料中加入Soy配料:HouseBlend + Mocha + Soy
    10         beverage2 = new Whip(beverage2);//在饮料中加入Whip配料:HouseBlend + Mocha + Whip
    11         System.out.println(beverage2.getDescription() + " $" + beverage2.cost());//结算
    12         
    13         Beverage beverage3 = new Whip( new Soy( new Mocha( new HouseBlend())));//这个和beverage2是一样的只是写法不同,认真观察
    14         System.out.println(beverage3.getDescription() + " $" + beverage3.cost());//结算
    15     }
    16 }
    StarbuzzCoffee

    编译运行结果:

    总结:

      主饮料和配料都继承自相同的Beverage抽象类,不过为了区分主饮料和配料的不同,我们在配料和Beverage抽象类之间有多了一个CondimentDecorator接口。

       主饮料实现时,只要getDescription()和cost()方法返回自己的名称和价格就好。配料中则多了一个Beverage对象,getDescription()和cost()方法不仅要返回自己的名称和价格,还要将自己修饰的Beverage对象的名称和价格一起算上。

    在Java中的Java.io类中使用的就是装饰者模式,有兴趣可以自己搜索资料。

    思想提炼:

      1.对扩展开放,对修改关闭

  • 相关阅读:
    【前端大神面考面试官系列】入门Vue全家桶
    【综合篇】浏览器的工作原理:浏览器幕后揭秘
    【星云测试】开发者测试(2)-采用精准测试工具对J2EE Guns开发框架进行测试
    【星云测试】开发者测试(3)-采用精准测试工具对springcloud微服务应用进行穿透测试
    【星云测试】开发者测试(4)-采用精准测试工具对dubbo微服务应用进行测试
    【星云测试】精准测试的软件产品质量效率变化分析
    巧用location.hash保存页面状态
    全面解析ASP.NET MVC模块化架构方案
    在多线程编程中lock(string){...}隐藏的机关
    注释是恶魔,请不要再写一行注释
  • 原文地址:https://www.cnblogs.com/lanshanxiao/p/7994320.html
Copyright © 2011-2022 走看看