菜单

Java设计模式之装饰模式趣谈,设计模式之装饰者模式

2020年1月11日 - 4166am金沙下载
Java设计模式之装饰模式趣谈,设计模式之装饰者模式

本文由码农网 –
鲁阿皓原创,转载请看清文末的转载要求,欢迎参与我们的付费投稿计划!

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

前情提要:

  举个例子:星巴兹咖啡(不是星巴克)

JVM:”上次给我招的工人不错啊!”

  星巴兹扩张速度太快了,他们准备更新订单系统,以合乎他们的饮料供应要求。他们的要求是这样子的:购买咖啡时,可以要求在其中加入各种调料,例如:蒸奶(Steamed
Milk)、豆浆(Soy)、摩卡(Mocha,也就是巧克力风味)或者覆盖奶泡。星巴兹会根据所加入的调料不同收取不同的费用。所以订单系统必须考虑到这些调料的部分。

oo程序员:”………..”

  先来进行第一次尝试:

JVM:”现在来我开的博物馆生意越来越好了,原来”舞台剧”的方式已经不能满足顾客的需求了”

  图片 1

oo程序员:”………..”

  哇塞!这简直是“类爆炸”!很明显,按照上面做出来的的系统同样创造了一个维护噩梦。如果调料Milk价格上涨,怎么办?新增加一种调料时,就会诞生多少种新的咖啡?造成这样维护上的困难,违背了我们的设计原则:多用组合,少用继承;要针对接口编程,而不是针对实现编程。

JVM:”我决定要换一种运营模式,把每个演播厅都租出去,让那些想表演节目的对象们来租演播厅和相关器械,这样我就能坐地收钱了!”

  那我们就换一种方式,先从Beverage基类入手,加上实例变量代表是否加上调料(牛奶、豆浆、摩卡、奶泡、辣椒……)

oo程序员:”………..”

  图片 2

JVM:”合伙干吧?怎么样?你三我七!”

  现在加入子类,每个类代表一种饮料。

oo程序员:”………..”

 图片 3

JVM:”四六?”

  认真想一下上面的方法还是有一些潜在的问题。当哪些需求或因素改变时会影响这个设计?

oo程序员:”成交!先说说需求。”

  1.当调料价格的改变会使我们更改现有代码。

JVM:”首先有不同类型的演播厅和不同的装饰品/器械,每种物品都要付一定的租金,你要做的就是一件事,把总租金(演播厅+饰品/器械)算出来。”

  2.一旦出现新的调料,我们就需要加上新的方法,并改变超类中的cost()方法。

oo程序员:”把价格表给我!”

  3.以后可能会开发出新饮料。对这些饮料而言(例如:冰茶、绿豆沙冰),某些调料可能并不适合,但是在这个设计方式中,Tea子类仍将继承那些不适合的方法,例如:hasWhip()
(加奶泡)。

卡通演播厅(CartoonStudio)     100

小丑演播厅(JokerStudio) 150

超级演播厅(SuperStudio) 300

气球(Balloon)                 10

灯光(Lamplight) 25

麦克风(Microphone) 20

  4.万一顾客想要双倍牛奶咖啡,怎么办?

最后还写下了这个:

  在此我们将介绍最重要的设计原则之一

public abstract class Anything_ex()
{
   String description=" ";
   public String getDescription()
   {
      return description;
   }
   public abstract int cost();
}

  类应该对扩展开放,对修改关闭(开放封闭原则)

仔细一想也对,无论是演播厅还是装饰品,都需要描述(description)和cost(价格),写一个共同的父类无可厚非。

  现在我们介绍今天的主角:装扮者模式

接着写下你设计的第一个类:

 
 以装饰者构造饮料订单

class CartoonandBalloon extends Anything_ex
{
   ....
   public int cost()
   {
      return 100+10;
   }
}   //带气球的卡通演播厅

  1.以DarkRoast对象开始

第二个:

  图片 4

class CartoonandLamplight extends Anything_ex
{
   ...
   public int cost()
   {
      return 100+25;
   }
}  //带灯光的卡通演播厅

  2.顾客想要摩卡(Mocha),所以建立一个Mocha对象,并用它将DarkRoast对象包装(wrap)起来。

第三个:
。。。。。

  图片 5

没有第三个了!这样写下去可是无穷无尽的!没办法,换个思路。

  3.顾客也想要奶泡(Whip),所以需要建立一个Whip装饰者,并用它将Mocha对象包装起来。别忘了,DarkRoast继承自Beverage,且有一个cost()方法,用来计算饮料价格。

在演播厅里,无论什么装饰品都有可能出现,可以把演播厅+饰品看成一个整体,通过饰品相应的has和set来控制饰品,这样的话,设计出来的类如下:

  图片 6

class CartoonStudio extends Anything_ex
{
    private  boolean Balloon=false;
    .... //省略其他变量,这里只以气球为例
    public boolean hasBalloon()
    {
        return Ballon;
    }
    public void setBallon()
    {
        Balloon=true;
    }
    .......//省略其他has/set方法
    public int cost()
    {
        int cost=100; //卡通演播厅的初始价格为100
        if(hasBalloon)
        {
            cost+=10;
        }
        else if(hasXXX).....//省略类推下来的代码

        return cost;
    }

}

  4.顾客其实对奶泡情有独钟,所以点了双倍的奶泡.

这个看起来好多了,不用写大爆炸数量的类,虽然类写起来又臭(无数的has/set)又长(的确很长)。。。。。

  图片 7

但是有没有更好的方案?

  5.现在该结账了

答案当然是有的,不过我们必须先明确一下,上述设计的缺点。

  图片 8

  好了,这是目前我们了解的装饰者模式:

下面让我们看看。装饰者模式是如何解决上面问题的。

  1.装饰者和被装饰者对象有相同的超类型。

装饰者模式:动态的将责任加到对象上,若要扩展功能,装饰者提供了比继承更有弹性的替代方案。

  2.你可以用一个或者多个装饰者包装一个对象。

首先,我们先将演播厅和他的装饰者们分开,让装饰者继承另一个类:

  3.在任何需要原始对象(被包装的)的场合,可以用装饰过的对象代替它。

public abstract class Decorater_ex extends Anyting_ex
{
      public abstract String getDescription();
}

  4.装饰者可以在所委托被装饰者的行为之前或之后,加上自己的行为,以达到特定的目的。  

让装饰者子类重新实现getDescription()即可。

  5.对象可以在任何时候被装饰,所以在运行时动态地、不限量地使用你喜欢的装饰者来装饰对象,

现在我们的思路是:用装饰者装饰演播厅,例如,一个带麦克风和气球的卡通演播厅,就先让气球装饰卡通演播厅,再让麦克风装饰“带气球的卡通演播厅”

  定义装饰者模式:

先让我们分别实现这3个类:

  动态的将责任附加到对象上。想要扩展功能,装饰者提供比继承更有弹性的替代方案。

卡通演播厅:

  我们来看一下类图:

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图