设计模式三之装饰者模式1

  装饰者模式,真是越来越生活化了,其实设计不就是源于生活高于生活吗?人类,一般总是把生活中观察的东西作为原料才能抽象出东西。装饰者模式,就是用各种装饰者对象来给被装饰者装饰,达到人们的多种多样的需求。不举咖啡的例子,实在没喝过几杯正式的咖啡。考虑炒饭,主要的原材料就是饭,但是变种非常多,近几天我就吃过和有深印象的,扬州炒饭、生牛肉炒饭、五香肉丁炒饭、XO酱海鲜炒饭、黄金炒饭、蛋炒饭等,像什么牛肉、葱花、肉丁、鸡蛋就是装饰者了,厨师用他们炒出(装饰出)各种饭。这种模式的优点是可以订制各种各样的需求,不再面临类爆炸的问题,我们只需要用组合就可以解决问题了。

  怎么实现呢?

  

首先看,这是一个抽象被装饰者类,所谓的饭。
package com.csshu;

/**
 * 抽象的组件类,饮料基类,抽象类,是所有饮料的基础类,这里也可以设计成接口
 * @author shujianhua
 *
 */
public abstract class Beverage {
    String description = "Unknown Beverage";
    
    // 在子类中必须重写这个类
    public String getDescription(){
        return description;
    }
    
    // 抽象类,子类必须重写它
    public abstract double cost();

}
可以设计成接口也可以是抽象类。

下面这个是装饰者类的抽象类
package com.csshu;

/**
 * 调料装饰者类,抽象的,简称抽象的装饰者类,由众多调料来继承它,属于装饰者类的抽象类
 * 为什么用继承,因为保持类型一致。
 * @author shujianhua
 *
 */
public abstract class CondimentDecorator extends Beverage{
    
    // 抽象类,子类必须重写它
    public abstract String getDescription();

}
为什么要继承被装饰者类,为了保持类型一致,以后装饰的时候方便,可以说都是大地之物。

下面这个是具体的被装饰者类
package com.csshu;

/**
 * 这是具体的组件类,属于饮料类的一种,属于最原始的东西,比如一杯原味奶茶
 * @author shujianhua
 *
 */
public class Espresso extends Beverage{
    
    // 考虑饮料的最原始名字,一杯原味奶茶
    public Espresso(){
        description = "Espresso";  // 这个是继承,所以可以用父类的变量
    }
    @Override
    public double cost() {
        return 1.99;
    }

}

package com.csshu;

/**
 * 这是具体的组件类,属于饮料类的一种,属于最原始的东西,比如一杯原味奶茶
 * @author shujianhua
 *
 */
public class HouseBlend extends Beverage{
    
    // 考虑饮料的最原始名字,一杯原味奶茶
    public HouseBlend(){
        description = "HouseBlend";  // 这个是继承,所以可以用父类的变量
    }
    @Override
    public double cost() {
        return 0.99;
    }

}

下面是具体的被装饰者类,
package com.csshu;

/**
 * 调料装饰者类,具体的,具体的装饰者类
 * @author shujianhua
 *
 */
public class Mocha extends CondimentDecorator{
    Beverage beverage;
    
    // 通过构造函数来实现包裹类,来装饰
    public Mocha(Beverage beverage){
        this.beverage = beverage;
    }
    
    // 这个叫做委托
    @Override
    public double cost() {
        return 0.20+beverage.cost();   
    }

    // 这个叫做委托delegation,在最后的输出类中可以吧描述,装饰者全部输出
    @Override
    public String getDescription() {
        return beverage.getDescription()+",Mocha";
    }

}

package com.csshu;

/**
 * 调料装饰者类,具体的,具体的装饰者类
 * @author shujianhua
 *
 */
public class Soy extends CondimentDecorator{
    Beverage beverage;
    
    // 通过构造函数来实现包裹类,来装饰
    public Soy(Beverage beverage){
        this.beverage = beverage;
    }
    
    // 这个叫做委托
    @Override
    public double cost() {
        return 0.39+beverage.cost();   
    }

    // 这个叫做委托delegation,在最后的输出类中可以吧描述,装饰者全部输出
    @Override
    public String getDescription() {
        return beverage.getDescription()+",Soy";
    }

}

package com.csshu;

/**
 * 调料装饰者类,具体的,具体的装饰者类
 * @author shujianhua
 *
 */
public class Whip extends CondimentDecorator{
    Beverage beverage;
    
    // 通过构造函数来实现包裹类,来装饰
    public Whip(Beverage beverage){
        this.beverage = beverage;
    }
    
    // 这个叫做委托
    @Override
    public double cost() {
        return 0.53+beverage.cost();   
    }

    // 这个叫做委托delegation,在最后的输出类中可以吧描述,装饰者全部输出
    @Override
    public String getDescription() {
        return beverage.getDescription()+",Whip";
    }

}

发现上面并没有上面多大的不同。。

接下来是入口main函数,
package com.csshu;

/**
 * 这里是允许装饰者模式的入口。
 * 我们来看,Beverage是抽象的组件类,HouseBlend和Espresso是具体的组件类
 * CondimentDecorator是抽象的装饰者类,Mocha和Soy以及Whip是具体的装饰者类
 * @author shujianhua
 *
 */
public class DecoratorEnter {

    public static void main(String[] args) {
        
        Beverage beverage1 = new Espresso();
        System.out.println(beverage1.cost()+"dao,"+beverage1.getDescription());
        
        Beverage beverage = new HouseBlend();
        beverage = new Mocha(beverage);  // 这里就是包装者,包进去了,其实装饰者装饰的顺序不重要
        beverage = new Soy(beverage);
        beverage = new Whip(beverage);
        System.out.println(beverage.cost()+"dao,"+beverage.getDescription());
        
        
    }

}

可以看到,首先new出了一个实体类,然后实体类的引用继续迭代引用其它装饰者包裹的新类。虽然是不断地引用其它,但是实体类的引用在这里面获得了很多新的属性。关键就是委托
(delegation)和接口的使用,一层层的传进去,最后一层层地传出来。

 

posted @ 2015-11-11 23:54  likeshu  阅读(138)  评论(0编辑  收藏  举报