疯狂java


您现在的位置: 疯狂软件 >> 新闻资讯 >> 正文

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


 

   

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

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

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

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

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

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

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

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

  JVM:”四六?”

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

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

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

  卡通演播厅(CartoonStudio) 100

  小丑演播厅(JokerStudio) 150

  超级演播厅(SuperStudio) 300

  气球(Balloon) 10

  灯光(Lamplight) 25

  麦克风(Microphone) 20

  最后还写下了这个:

  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;

  }

  } //带气球的卡通演播厅

  第二个:

  class CartoonandLamplight extends Anything_ex

  {

  ...

  public int cost()

  {

  return 100+25;

  }

  } //带灯光的卡通演播厅

  第三个:

  。。。。。

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

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

  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;

  }

  }

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

  但是有没有更好的方案?

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

  1.臭

  2.长

  3.当饰品的租金改变的时候,必须修改所有演播厅的代码(cost部分),我们当然不想这样,我们想尽可能的少修改代码(松耦合)。

  4.没有面对超类/接口编程。

  5.没有将变化的部分独立开。

  6.组合可能是更好的解决方案。

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

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

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

  public abstract class Decorater_ex extends Anyting_ex

  {

  public abstract String getDescription();

  }

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

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

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

  卡通演播厅:

  class CortoonStudio extends Anything_ex

  {

  public CortoonStudio()

  {

  description="CortonStudio";

  }

  publuc int cost()

  {

  return 100;

  }

  }

  麦克风:

  class Microphone extends Decorater_ex

  {

  private Anything_ex studio;

  public Microphone(Anything_ex studio )

  {

  this.studio=studio;

  }

  public String getDescription()

  {

  return studio.getDescription()+",Microphone";

  }

  public int cost()

  {

  return studio.cost()+20;

  }

  }

  气球:

  class Balloon extends Decorater_ex

  {

  private Anything_ex studio;

  public Balloon(Anything_ex studio )

  {

  this.studio=studio;

  }

  public String getDescription()

  {

  return studio.getDescription()+",Balloon";

  }

  public int cost()

  {

  return studio.cost()+10 ;

  }

  }

  代码:

  Anything_ex CortoonStudio =new CortoonStudio(); //一个卡通演播厅对象

  CortoonStudio=new Microphone(CortoonStudio); //拿麦克风装饰

  CortoonStudio=new Balloon(CortoonStudio); //拿气球装饰

  System.out.println(CortoonStudio.getDescription()+"="+CortoonStudio.cost());

  输出结果:

  CortonStudio,Microphone,Balloon=130

  结果是正确的。

  这样写很好的解决了上面的问题。

  1.运用组合进行扩展,使当价格改变的时候,只需要修改本身的代码。

  2.面对超类/接口编程,使饰品增加种类的时候,并不需要修改被装饰者的代码。

  3.开放——关闭原则 :代码应该对扩展开放,对修改关闭。

  缺陷:

  1.子类繁多,影响理解代码(java I/O就是装饰者模式哦。。。)。

  2.无法应用于需要具体类的场景。