设计模式之装饰者模式

早晨有时候会去附近煎饼店买煎饼,煎饼店有卖咸味煎饼、甜味煎饼、不加甜味也不加咸味的煎饼。在煎饼制作的过程中,煎饼阿姨会问,"需要添加点什么吗,有鸡蛋、火腿、熏肉......"之类的话。我若选择咸味味煎饼加鸡蛋加火腿的时候,我需要付给阿姨的钱金额=咸味烧饼的钱+鸡蛋的钱+火腿的钱。现有需求:为煎饼店开发一套订单系统,自动为顾客所点的不同口味且添加了不同添加辅料(鸡蛋、火腿、大葱、熏肉、生菜等)的煎饼算出最终售价。

当我们看到如下图所示的那么多的类,肯定会很觉得写那么多类的开发者很脑残。

设计模式之装饰者模式_第1张图片

这仅仅只考虑三种辅料(鸡蛋,火腿,熏肉),当需要考虑大葱,生菜等,类的数量迅速的增多了很多。很明显,这种方法是愚蠢的。

面对上面糟糕的方法,我们重新想出新的方法,来避免井喷式增长的类的问题。首先,编写虚类Pancake,代码:

package com.raze.progress;

/**
 * @author DJM
 * @version 1.0
 */
public abstract class Pancake {
    
    private String description;
    
    private Boolean egg;
    
    private Boolean ham;
    
    private Boolean pork;
    
    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public Boolean getEgg() {
        return egg;
    }

    public void setEgg(Boolean egg) {
        this.egg = egg;
    }

    public Boolean getHam() {
        return ham;
    }

    public void setHam(Boolean ham) {
        this.ham = ham;
    }

    public Boolean getPork() {
        return pork;
    }

    public void setPork(Boolean pork) {
        this.pork = pork;
    }

    public abstract float cost();

}

这样的弊端也很明显,首先根据开闭原则(Open close principle)的要求,对扩展开放,对修改关闭。这样就已不适用,因为当煎饼店添加了新的辅料,我们不得不修改类Pancake类。另外,当客户点了两个及以上的鸡蛋的时候,这种方法彻底瘫痪了。所以这种方法,也需要舍弃。

既要避免类的数量井喷式的增长,又要符合开闭原则。我编写了一个虚类Pancake,代码如下:

package com.raze.decorator.component;

/**
 * @author DJM
 * @version 1.0
 */
public abstract class Pancake {
    
    private String description;
    
    private Float price;
    
    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
    
    public Float getPrice() {
        return price;
    }

    public void setPrice(Float price) {
        this.price = price;
    }

    public abstract float cost();

}

在虚类Pancake和继承虚类Pancake的子类的中间层写了一个类ConcretePancake,具体代码如下:

package com.raze.decorator.component.concrete;

import com.raze.decorator.component.Pancake;

public class ConcretePancake extends Pancake{
    
    @Override
    public float cost() {
        return getPrice();
    }

}

并编写三个继承了类ConcretePancake的子类,具体代码如下:

package com.raze.decorator.component.concrete;

/**
 * 无添加煎饼
 * @author DJM
 * @version 1.0
 */
public class FanclPancake extends ConcretePancake {
    
    public FanclPancake(){
        setDescription("FanclPancake");
        setPrice(3.0f);
    }

}
package com.raze.decorator.component.concrete;

/**
 * 咸煎饼
 * @author DJM
 * @version 1.0
 */
public class SalinePackage extends ConcretePancake {
    
    public SalinePackage() {
        setDescription("SalinePackage");
        setPrice(4.0f);
    }

}
package com.raze.decorator.component.concrete;

/**
 * 甜煎饼
 * @author DJM
 * @version 1.0
 */
public class SugarPancake extends ConcretePancake {
    
    public SugarPancake(){
        setDescription("SugarPancake");
        setPrice(3.5f);
    }

}

定义一个装饰类Decorator,代码:

package com.raze.decorator.decorator;

import com.raze.decorator.component.Pancake;

/**
 * 装饰类
 * @author DJM
 * @version 1.0
 */
public class Decorator extends Pancake {
    
    private Pancake pancake;

    public Pancake getPancake() {
        return pancake;
    }

    public void setPancake(Pancake pancake) {
        this.pancake = pancake;
    }
    
    public Decorator(Pancake pancake){
        this.pancake = pancake;
    }

    @Override
    public float cost() {
        return pancake.cost()+super.getPrice();
    }

    @Override
    public String getDescription() {
        return pancake.getDescription().concat("-").concat(super.getDescription());
    }
    
}

并为辅料定义类,继承于类Decorator,所有的辅料类如下图:

设计模式之装饰者模式_第2张图片

选出一个类Vegetable的代码进行展示:

package com.raze.decorator.decorator.concrete;

import com.raze.decorator.component.Pancake;
import com.raze.decorator.decorator.Decorator;

/**
 * 生菜
 * @author DJM
 * @version 1.0
 */
public class Vegetable extends Decorator {
    
    public Vegetable(Pancake pancake) {
        super(pancake);
        setDescription("Vegetable");
        setPrice(0.5f);
    }

}

现在进行测试,具体代码如下:

package com.raze.decorator;

import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.raze.decorator.component.Pancake;
import com.raze.decorator.component.concrete.FanclPancake;
import com.raze.decorator.decorator.concrete.Egg;
import com.raze.decorator.decorator.concrete.Ham;
import com.raze.decorator.decorator.concrete.Pork;
import com.raze.decorator.decorator.concrete.Vegetable;

public class MyPancakeTest {
    
    private static final Logger logger = LoggerFactory.getLogger(MyPancakeTest.class);
    
    @Test
    public void pancake(){
        Pancake pancake = new FanclPancake(); 
        float myCost = pancake.cost();
        logger.info("The pancake costs {} yuan.The description is {}.", myCost, pancake.getDescription());
        
        pancake = new Vegetable(pancake);
        myCost = pancake.cost();
        logger.info("The pancake costs {} yuan.The description is {}.", myCost, pancake.getDescription());
        
        pancake = new Egg(pancake);
        myCost = pancake.cost();
        logger.info("The pancake costs {} yuan.The description is {}.", myCost, pancake.getDescription());
        
        pancake = new Ham(pancake);
        myCost = pancake.cost();
        logger.info("The pancake costs {} yuan.The description is {}.", myCost, pancake.getDescription());
        
        
        pancake = new Pork(pancake);
        myCost = pancake.cost();
        logger.info("The pancake costs {} yuan.The description is {}.", myCost, pancake.getDescription());
        
        pancake = new Pork(pancake);
        myCost = pancake.cost();
        logger.info("The pancake costs {} yuan.The description is {}.", myCost, pancake.getDescription());
        
        pancake = new Ham(pancake);
        myCost = pancake.cost();
        logger.info("The pancake costs {} yuan.The description is {}.", myCost, pancake.getDescription());
    }

}

控制台打印的结果为:


根据类的关系,得到如下图:

设计模式之装饰者模式_第3张图片

你可能感兴趣的:(设计模式之装饰者模式)