码迷,mamicode.com
首页 > 其他好文 > 详细

设计模式之装饰者模式

时间:2015-09-21 19:49:06      阅读:173      评论:0      收藏:0      [点我收藏+]

标签:

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

技术分享

这还仅仅只考虑三种辅料(鸡蛋,火腿,熏肉),当需要考虑大葱,生菜等,类一下子增多了很多很多。很明显,我们不可以采用此种方法。

当我们编写虚类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的子类,具体代码如下:

package com.raze.decorator.component.concrete;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.raze.decorator.component.Pancake;

/**
 * 无添加煎饼
 * @author DJM
 * @version 1.0
 */
public class FanclPancake extends Pancake {
    
    private static final Logger logger = LoggerFactory.getLogger(FanclPancake.class);
    
    public FanclPancake(){
        setDescription("FanclPancake");
        setPrice(3.0f);
    }

    @Override
    public float cost() {
        logger.info("The pancake of {} costs {} yuan.", getDescription(), getPrice());
        return getPrice();
    }

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

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.raze.decorator.component.Pancake;

/**
 * 咸煎饼
 * @author DJM
 * @version 1.0
 */
public class SalinePackage extends Pancake {
    
    private static final Logger logger = LoggerFactory.getLogger(SalinePackage.class);

    public SalinePackage() {
        setDescription("SalinePackage");
        setPrice(4.0f);
    }
    
    @Override
    public float cost() {
        logger.info("The pancake of {} costs {} yuan.", getDescription(), getPrice());
        return getPrice();
    }

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

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.raze.decorator.component.Pancake;

/**
 * 甜煎饼
 * @author DJM
 * @version 1.0
 */
public class SugarPancake extends Pancake {
    
    private static final Logger logger = LoggerFactory.getLogger(SugarPancake.class);
    
    public SugarPancake(){
        setDescription("SugarPancake");
        setPrice(3.5f);
    }
    
    @Override
    public float cost() {
        logger.info("The pancake of {} costs {} yuan.", getDescription(), getPrice());
        return getPrice();
    }

}

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

package com.raze.decorator.decorator;

import com.raze.decorator.component.Pancake;

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

    public Pancake getPancake() {
        return pancake;
    }

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

并为辅料定义类,所有的类如下图:

技术分享

选出一个类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) {
        setPancake(pancake);
    }

    @Override
    public float cost() {
        return super.getPancake().cost()+1.0f;
    }

}

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

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.Decorator;
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 MyDecoratorTest {
    
    private static final Logger logger = LoggerFactory.getLogger(MyDecoratorTest.class);
    
    @Test
    public void decorator(){
        Pancake pancake = new FanclPancake(); 
        float myCost = pancake.cost();
        logger.info("The pancake costs {} yuan.", myCost);
        
        Decorator decorator = new Vegetable(pancake);
        myCost = decorator.cost();
        logger.info("The pancake costs {} yuan.", myCost);
        
        decorator = new Egg(pancake);
        myCost = decorator.cost();
        logger.info("The pancake costs {} yuan.", myCost);
        
        decorator = new Ham(decorator);
        myCost = decorator.cost();
        logger.info("The pancake costs {} yuan.", myCost);
        
        
        decorator = new Pork(decorator);
        myCost = decorator.cost();
        logger.info("The pancake costs {} yuan.", myCost);
        
        decorator = new Pork(decorator);
        myCost = decorator.cost();
        logger.info("The pancake costs {} yuan.", myCost);
    }

}

控制台打印的结果为:

技术分享

认真思考下图,可装饰者设计模式的思路得到新的梳理:

技术分享

设计模式之装饰者模式

标签:

原文地址:http://my.oschina.net/dengjianming/blog/509306

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!