head frist 设计模式学习之 装饰者模式

前情提要:http://blog.csdn.net/baidu_30889437/article/details/50917814  
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.长
画外:玩笑,23333
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.无法应用于需要具体类的场景。

 这篇文章到此差不多结束了,作者功力尚浅,文章如有不正之处请读者指出,海涵。

本文为博主原创,首发自码农网:http://www.codeceo.com/article/java-decorator-pattern.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值