设计模式 | 第三篇:装饰者模式

早上,我去鸡蛋饼小摊拿买了一块鸡蛋饼,加了两煎蛋,加了火腿肠,加了生菜,还加了根油条。

吃的好饱。。。

人与动物区别在于,人不仅会吃,而且会思考。所以,这种场景,作为程序员,你应该怎么设计?

好说!

/**
 * 反面教材1(BOOM!类爆炸)
 */
class 鸡蛋饼{
    public double cost() {
        return 3;
    }
}
class 鸡蛋饼With鸡蛋 extends 鸡蛋饼{
    public double cost() {
        return super.cost() + 0.5;
    }
}

class 鸡蛋饼With火腿 extends 鸡蛋饼{
    public double cost() {
        return super.cost() + 1;
    }
}
/**
 * 反面教材2(违反开闭原则:类应该对扩展开放,对修改关闭)
 * 以后鸡蛋价格变了,或者加两个鸡蛋,或者再加一种别的调料,想一下你怎么设计?
 */

class 鸡蛋饼2{
    
    /**
     *有鸡蛋
     */
    private boolean hasEgg;
    
    /**
     *有火腿
     */
    private boolean hasHuotui;
    
    public double cost() {
        double basecost =3;
        if(hasEgg) {
            basecost +=0.5;
        }
        if(hasHuotui) {
            basecost +=1;
        }
        
        return basecost;
    }

    /**
     * @return the hasEgg
     */
    public boolean isHasEgg() {
        return hasEgg;
    }

    /**
     * @param hasEgg the hasEgg to set
     */
    public void setHasEgg(boolean hasEgg) {
        this.hasEgg = hasEgg;
    }

    /**
     * @return the hasHuotui
     */
    public boolean isHasHuotui() {
        return hasHuotui;
    }

    /**
     * @param hasHuotui the hasHuotui to set
     */
    public void setHasHuotui(boolean hasHuotui) {
        this.hasHuotui = hasHuotui;
    }
}

 

装饰者概念

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

设计理念

  当我们设计的类不能满足我们的需求的时候,我们可能设计一个类去继承它,但是这样就会使对象之间高度的耦合。

  这时,我们就可以换一种思路,将不能满足我们需求的类A嵌入到要扩展的功能的类B当中。

  这里注意,我们将要扩展的功能设计为一个类B,当这个类构造时可以引入A,B将持有A对象实例。

  这种方法,我们称之为:装饰者模式

使用场景

  装饰模式的应用在java的I/O流中最为显著。

设计原则

  对扩展开放,对修改关闭。

UML类图

设计模式 | 第三篇:装饰者模式

 

 

 示例

抽象组件

package com.study.headfirst.decorator;

/**
 * 抽象组件
 * @author mdl
 * @date 2019/12/05
 */
public abstract class Pancake {

    public String desc = "我不是一个具体的饼";

    /**
     * @return the desc
     */
    public String getDesc() {
        return desc;
    }

    public abstract double cost();

}

鸡蛋饼(具体组件A)

package com.study.headfirst.decorator;

/**
 * @author mdl
 * @date 2019/12/05
 */
public class TornCake extends Pancake{
    
    public TornCake() {
        desc ="鸡蛋饼";
    }

    /* (non-Javadoc)
     * @see com.study.headfirst.decorator.Pancake#cost()
     */
    @Override
    public double cost() {
        // TODO Auto-generated method stub
         return 4;
    }

}

肉夹馍(具体组件B)

package com.study.headfirst.decorator;

/**
 * @author mdl
 * @date 2019/12/05
 */
public class Roujiamo extends Pancake{
    
    public Roujiamo() {
        desc ="肉夹馍";
    }
    
    
    /* (non-Javadoc)
     * @see com.study.headfirst.decorator.Pancake#cost()
     */
    @Override
    public double cost() {
        // TODO Auto-generated method stub
         return 5;
    }

}

抽象装饰者

package com.study.headfirst.decorator;

/**
 * 抽象装饰者
 * @author mdl
 * @date 2019/12/05
 */
public abstract class Condiment extends Pancake{
    
    public abstract String getDesc();
    
}

鸡蛋(具体装饰者)

package com.study.headfirst.decorator;

/**
 * 鸡蛋(具体装饰者)
 * @author mdl
 * @date 2019/12/05
 */
public class Egg extends Condiment{
    
    private Pancake cake;
    
    public Egg(Pancake cake) {
        this.cake = cake;
    }
    

    /* (non-Javadoc)
     * @see com.study.headfirst.decorator.Condiment#desc()
     */
    @Override
    public String getDesc() {
        // TODO Auto-generated method stub
         return cake.getDesc() + ",鸡蛋";
    }

    /* (non-Javadoc)
     * @see com.study.headfirst.decorator.Pancake#cost()
     */
    @Override
    public double cost() {
        // TODO Auto-generated method stub
         return cake.cost() + 1;
    }

}

火腿(具体装饰者)

设计模式 | 第三篇:装饰者模式
package com.study.headfirst.decorator;

/**
 * 火腿(具体装饰者)
 * @author mdl
 * @date 2019/12/05
 */
public class Ham extends Condiment{

    private Pancake cake;
    
    public Ham(Pancake cake) {
        this.cake = cake;
    }
    
    /* (non-Javadoc)
     * @see com.study.headfirst.decorator.Condiment#desc()
     */
    @Override
    public String getDesc() {
        // TODO Auto-generated method stub
         return cake.getDesc() + ", 火腿";
    }

    /* (non-Javadoc)
     * @see com.study.headfirst.decorator.Pancake#cost()
     */
    @Override
    public double cost() {
        // TODO Auto-generated method stub
         return cake.cost() + 1.5;
    }

}
View Code

生菜(具体装饰者)

设计模式 | 第三篇:装饰者模式
package com.study.headfirst.decorator;

/**
 * 生菜(具体装饰者)
 * @author mdl
 * @date 2019/12/05
 */
public class ShenCai extends Condiment{
    
    private Pancake cake;
    
    public ShenCai(Pancake cake) {
        this.cake = cake;
    }

    /* (non-Javadoc)
     * @see com.study.headfirst.decorator.Condiment#desc()
     */
    @Override
    public String getDesc() {
        // TODO Auto-generated method stub
         return cake.getDesc() + ", 生菜";
    }

    /* (non-Javadoc)
     * @see com.study.headfirst.decorator.Pancake#cost()
     */
    @Override
    public double cost() {
        // TODO Auto-generated method stub
         return cake.cost() + 0.5;
    }

}
View Code

测试

package com.study.headfirst.decorator;

/**
 * @author mdl
 * @date 2019/12/05
 */
public class Test {

    public static void main(String[] args) {
        // 点个鸡蛋饼,啥都不加
        Pancake cake =new TornCake();
        System.out.println(cake.getDesc() + ",价钱:" + cake.cost());
        
        // 点个鸡蛋饼,加两根火腿,加生菜
        Pancake cake2 =new TornCake();
        cake2 =new Ham(cake2);
        cake2 =new Ham(cake2);
        cake2 =new ShenCai(cake2);
        System.out.println(cake2.getDesc() + ",价钱:" + cake2.cost());
    }
    
}

设计模式 | 第三篇:装饰者模式

 

上一篇:【PAT B1020】 月饼


下一篇:UVA1629 Cake slicing