`

装饰模式梳理

阅读更多

现在又这么一个场景
一家饭店经营多年后,终于开出了第100家房间,但是现在面临一个问题!就是菜单的更新,如果菜单中一个菜的更改的话,那么就需要更改所有的菜单。
简单的说家店有10本菜谱,那么100家就需要更新10*100,那是一个很恐怖的数据!
那怎么办呢,这个时候就需要设计一套电子菜单了!他们雇佣


 了BigSoft公司的精英来开发这套系统!

好,项目就紧张的开始了,前期的需求调研,评估,UC的形成,架构的设计,详细设计。。。。
本来认为是一个很简单的系统,设计时碰到了一个问题!因为这家店有一道招牌菜---鸡。
这个鸡的性别可以分为 公鸡,母鸡。它们的价格是不一样的
但是这个鸡的来源又可以分为 中国产,日本产,不同产地的价格也是不一样的!

那这个菜单应该怎么设计呢。  是 鸡 ---- 中国公鸡,中国母鸡,日本公鸡,日本母鸡?


这样的话,将来又增加了来源美国鸡,若是鸡有了中性鸡呢?这些情况如何考虑?还是继续添加各种子类吗?

好吧!这个时候怎么办呢?伟大的BigSoft公司的精英们面对这点小问题当然是没问题了

就是采用了装饰模式,这里对于装饰模式的解释还是欠缺:



看代码;Chickren,就是被装饰的统一对象

package com.test.test.decoration; 

public abstract class Chickren { 
    
    String desc; 

    /* empty implement 
     * @see com.test.test.decoration.Chickren#cost() 
     */ 
    public abstract int cost(); 
    

    public String getDesc() { 
        return desc; 
    } 

    public void setDesc(String desc) { 
        this.desc = desc; 
    } 
    
} 

 

公鸡:

package com.test.test.decoration; 


public class Cock extends Chickren { 
    
    public Cock(){ 
        desc = "this is a cock,and it's price is $1.2"; 
    } 

    @Override 
    public int cost() { 
        return 12; 
    } 

    
} 

 


母鸡:

package com.test.test.decoration; 

public class Hen extends Chickren { 
    
    public Hen(){ 
        desc = "this is a hen "; 
    } 

    @Override 
    public int cost() { 
        return 10; 
    } 
    
} 

 
装饰类:

package com.test.test.decoration; 

public abstract class DecorationChickren extends Chickren{ 
     
    public abstract String getDesc(); 
    
    
}   

 

装饰者:
中国来的鸡

package com.test.test.decoration; 

/** 
* notice: 
* price is 15$ 
* desc: a hen from guangdong province which is so beautiful ,and it price is just 15$. 
* you just wait what ,come on baby ! 
* only one day, if you lost this time ,you will never forgive youself forever! 
* 
* @author inter12 
* 
*/ 
public class ChinaChickren extends DecorationChickren{ 

    private volatile Chickren chickren;  //这里声明为 volatile很关键! 
    
    public ChinaChickren(Chickren chickren){ 
        this.chickren = chickren; 
    } 
    
    @Override 
    public int cost() { 
        
        return chickren.cost() + 15; //具体的调用方式 
    } 

    @Override 
    public String getDesc() { 
        
        return chickren.getDesc() + "and it's not a hen ! also a china chickren! "; 
    } 
    
} 

 

日本来的鸡:

package com.test.test.decoration; 

/** 
* price is $10 
* desc :a chickren from japan,so delicious  
* @author inter12 
* 
*/ 
public class JapanChickren extends DecorationChickren { 
    
    public Chickren chick;  //注意,这里还是持有一个最初的父类接口,这样就可以做到随意的多级装饰 
    
    public JapanChickren(Chickren chick) { 
        
        this.chick = chick; 
    } 
    
    @Override 
    public String getDesc() { 
        
        return chick.getDesc()+"my god ,how delicious the chickren is!"; 
    } 

    public int cost() { 
        return chick.cost() + 10; 
    } 

} 

 


购买的人来了:

package com.test.test.decoration; 

public class ChickrenBuyer { 
    
    
    public static void main(String[] args) { 
        
//调用方式一 
//        Chickren chickren = new Hen(); 
//        chickren = new ChinaChickren(chickren); 
        
        //调用方式二 
        Chickren chickren = new ChinaChickren(new Hen()); 
        System.out.println("price:" + chickren.cost()); 
        System.out.println("desc:"  + chickren.getDesc()); 
        
        chickren = new JapanChickren(chickren); 
        System.out.println("price:" + chickren.cost()); 
        System.out.println("desc:"  + chickren.getDesc()); 
    } 
} 

 

是不是很熟悉的看到了java.io中的组合方式呢

这里做的不好的是 每个装饰的子类都有持有一个 Chickren对象,准确的应该是装饰类持有一个chickren对象,调用父类的构造方法
只改造了装饰者部分即可
下面的是改造版本:

package com.test.test.decoration; 

public abstract class DecorationChickren extends Chickren { 

    protected volatile Chickren chick; 

    public abstract String getDesc(); 

    public DecorationChickren(Chickren chickren) { 
        
        this.chick = chickren; 
    } 

    public Chickren getChickren() { 
        return chick; 
    } 

    public void setChickren(Chickren chickren) { 
        this.chick = chickren; 
    } 

    
} 

 

具体的装饰l;

package com.test.test.decoration; 

/** 
* notice: 
* price is 15$ 
* desc: a hen from guangdong province which is so beautiful ,and it price is just 15$. 
* you just wait what ,come on baby ! 
* only one day, if you lost this time ,you will never forgive youself forever! 
* 
* @author inter12 
* 
*/ 
public class ChinaChickren extends DecorationChickren{ 

    
    public ChinaChickren(Chickren chickren){ 
        super(chickren); 
    } 
    
    @Override 
    public int cost() { 
        
        return chick.cost() + 15; 
    } 

    @Override 
    public String getDesc() { 
        
        return chick.getDesc() + "and it's not a hen ! also a china chickren! "; 
    } 
    
} 

 

日本鸡:

package com.test.test.decoration; 

/** 
* price is $10 
* desc :a chickren from japan,so delicious  
* @author inter12 
* 
*/ 
public class JapanChickren extends DecorationChickren { 
    
    
    public JapanChickren(Chickren chick) { 
        super(chick); 
    } 
    
    @Override 
    public String getDesc() { 
        
        return chick.getDesc()+"my god ,how delicious the chickren is!"; 
    } 

    public int cost() { 
        return chick.cost() + 10; 
    } 

} 

 

总结:
1.适用于多维的系统,例如本案中就是个很经典例子。做菜,主料是鸡煲,鸡可以选择不同国家的鸡,鸡又可以采用不同的烧法,清蒸,红烧等。那么鸡和烧法就是两个维度,这样的情况下就可以猜装饰模式,在一个前提下,将不同的行为装饰上去。
2.语法结构上,一个抽象的主对象 一个抽象的装饰类,持有一个父类接口对象,所有继承装饰类的对象都必须持有父类接口引用,这样保证该继承路线的对象都能得到装饰!
3.装饰模式意味这一群装饰对象,并且反应了被装饰组件的类型。
4.装饰者会导致设计中出现许多小对象,如果过度使用,会让系统变的很复杂!
5.动态的将责任附加到对象上,是区别于继承的另一种方式!

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics