装饰器模式和多线程

装饰器模式和多线程

在HeadFirst中,有一个StuckBuzz的例子用来阐述装饰器模式,在这篇博文中,打算将同步编程和装饰器模式结合起来介绍一下。

背景

想象一个咖啡后台计费系统,需要计算一杯咖啡的价格。(或者多杯的价格)另外,我们需要饮料的种类和添加的调料。需求要在原材料的价格经常变化的条件下,减少数据的改动。

  1. 第一种写法
    使用继承的模式,类图的如下:
    饮料
public abstract class Beverage {
    String description = "abstract Beverage";
    //可以写入配置文件,不计入类属性
    final double MILK_PRICE = 2;
    final double SOY_PRICE = 1.5;
    final double MOCHA_PRICE = 3;
    final double WHIP_PRICE = 4;

    public Boolean getMilk() {
        return milk;
    }

    public void setMilk(Boolean milk) {
        this.milk = milk;
    }

    public Boolean getSoy() {
        return soy;
    }

    public void setSoy(Boolean soy) {
        this.soy = soy;
    }

    public Boolean getMocha() {
        return mocha;
    }

    public void setMocha(Boolean mocha) {
        this.mocha = mocha;
    }

    public Boolean getWhip() {
        return whip;
    }

    public void setWhip(Boolean whip) {
        this.whip = whip;
    }

    Boolean milk=false; //default, no add
    Boolean soy=false; //default, no add
    Boolean mocha=false;//default, no add
    Boolean whip=false;//default, no add



    public String getDescription(){
        return description;
    }

    public double cost() {
        double num = 0d;
        if (getMilk()) num += MILK_PRICE;
        if (getMocha()) num += MOCHA_PRICE;
        if (getSoy()) num += SOY_PRICE;
        if (getWhip()) num += WHIP_PRICE;
        return num;
    }


}

class HouseBlend extends Beverage{
    String description = "House Blend";
    double HOUSE_BLEND_PRICE = 15;
    public double cost(){
        return HOUSE_BLEND_PRICE + super.cost();
    }
}
  1. 加强需求
    调料和饮料单独分类,并响应大家对一种调料加双倍的需求,如何设计这个装饰器,就有很大的学问了。

在这里插入图片描述

在这个类图中,最大的特色就是CondimentDecorator是以component的形式并入Beverage中的。因为调料作为附加品,可以加可以不加,也可以加双份。牛奶和抹茶中的Beverage, 记录了当前的饮料的类型,注意哦,这里的饮料可以是加了Milk或者Mocha的咖啡呢,也就实现了加双份调料的功能!

代码如下:

public abstract class Beverage2 {
    String description = "abstract Beverage";

    public abstract double cost();

    public String getDescription(){
        return description;
    }

}

abstract class CondimentDecorator extends Beverage2{
    public abstract String getDescription();
}

//饮料
class Espresso extends Beverage2{
    public Espresso() {
        description = "Espresso";
    }

    public double cost(){
        return 1.99;
    }
}

class Mocha extends CondimentDecorator{
    public Mocha(Beverage2 beverage2) {
        this.beverage2 = beverage2;
    }

    Beverage2 beverage2;

    public String getDescription(){
        return beverage2.getDescription()+ ", Mocha";
    }

    @Override
    public synchronized double cost() {
        return .20 + beverage2.cost();
    }
}

class Milk extends CondimentDecorator{
    public Milk(Beverage2 beverage2) {
        this.beverage2 = beverage2;
    }

    Beverage2 beverage2;

    public String getDescription(){
        return beverage2.getDescription()+ ", Mocha";
    }

    @Override
    public synchronized double cost() {
        return .80 + beverage2.cost();
    }
}

Demo如下,注意包装的类,可以重复包装!

//类比于InputStream的装饰器模式
public class DecoratorTest {
    public static void main(String[] args) {
        //两份Mocha
        Beverage2 Espresso = new Espresso();
        Mocha mocha = new Mocha(Espresso);
        Mocha mocha_double = new Mocha(mocha);


        Beverage2 Espresso2 = new Espresso();
        Mocha mocha2 = new Mocha(Espresso2);
        Milk milk2 = new Milk(mocha2);

        System.out.println(mocha_double.getDescription() + " ¥" + mocha_double.cost());
        System.out.println(milk2.getDescription() + " ¥" + milk2.cost());
    }
}

Demo的显示如下:
在这里插入图片描述

与多线程的关系

如果一袋调料可以加入多杯饮料中,为了做一个库存系统,并且同时有3-5人共用这袋调料,那么如何分配这杯饮料呢?如果要在之前的代码的基础上进行重构,要如何做呢?

这个题目应该是开放的,笔者这里使用线程的封闭原则对调料进行控制,一次只能一个人用调料。

//线程封闭
class Condiments {
    private final Set<Beverage2> mySet = new HashSet<>();

    public synchronized void addBeverage(Beverage2 beverage2){
        mySet.add(beverage2);
    }

    public synchronized boolean containsBeverage(Beverage2 beverage2){
        return mySet.contains(beverage2);
    }
}

在JAVA中,最好的实现该方法的例子就是Collections.synchronizedXXX(XXX);
XXX可以为List, Map等等。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值