Decorator装饰者模式

Decorator装饰者模式

引入业务场景

这里写图片描述

当前有一家饮料店,饮料包括基础饮料,购买饮料时候,可以选择需要提那家的配料,及饮料杯大小类型,然后结算金额。其中,饮料和配料可以会新增很多种,或原原料或配料因销售不佳可能下架,或饮料或者配料单价可以修改,(饮料大小类型不变,及没有其他类型)

初级模型设计(不考虑饮料杯大小类型)

饮料为继承类,配料为变量

这里写图片描述

对应代码

Beverage

package headfirst.hd.decorator.old;

public abstract class Beverage {

    String description = "饮料";

    boolean pearl;
    boolean watermelon;
    boolean banana;
    boolean sugar;

    public String getDescription() {
        return description;
    }

    public abstract double cost();

    public boolean isPearl() {
        return pearl;
    }

    public void setPearl(boolean pearl) {
        this.pearl = pearl;
    }

    public boolean isWatermelon() {
        return watermelon;
    }

    public void setWatermelon(boolean watermelon) {
        this.watermelon = watermelon;
    }

    public boolean isBanana() {
        return banana;
    }

    public void setBanana(boolean banana) {
        this.banana = banana;
    }

    public boolean isSugar() {
        return sugar;
    }

    public void setSugar(boolean sugar) {
        this.sugar = sugar;
    }

    //辅助计算方法
    protected double condimentCost() {
        double cost = 0;
        if (isPearl()) {
            cost += 1.0;
        }

        if (isBanana()) {
            cost += 2.0;
        }

        if (isSugar()) {
            cost += 1.0;
        }

        if (isWatermelon()) {
            cost += 1.0;
        }

        return cost;
    }

}

H2CO3

package headfirst.hd.decorator.old;

public class H2CO3 extends Beverage {

    public H2CO3() {
        description = "碳酸饮料";
    }

    @Override
    public double cost() {
        //饮料基础价格
        double cost = 2.0;
        //配料价格
        cost += super.condimentCost();
        return cost;
    }

}

Coffee

package headfirst.hd.decorator.old;

public class Coffee extends Beverage {

    public Coffee() {
        description = "咖啡";
    }

    @Override
    public double cost() {
        //饮料基础价格
        double cost = 4.0;
        //配料价格
        cost += super.condimentCost();
        return cost;
    }

}

Fruit

package headfirst.hd.decorator.old;

public class Fruit extends Beverage {

    public Fruit() {
        description = "果汁饮料";
    }

    @Override
    public double cost() {
        //饮料基础价格
        double cost = 2.0;
        //配料价格
        cost += super.condimentCost();
        return cost;
    }

}

Tea

package headfirst.hd.decorator.old;

public class Tea extends Beverage {

    public Tea() {
        description = "茶饮料";
    }

    @Override
    public double cost() {
        //饮料基础价格
        double cost = 3.0;
        //配料价格
        cost += super.condimentCost();
        return cost;
    }

}

测试,买一杯果汁,加珍珠,加香蕉
TestDrive

package headfirst.hd.decorator.old;

public class TestDrive {

    public static void main(String[] args) {
        Beverage beverage = new Fruit();
        beverage.setPearl(true);
        beverage.setBanana(true);

        //果汁(2)+ 珍珠(1)+ 香蕉(2)
        System.out.println(beverage.cost());

    }

}

这里写图片描述

当前设计引发的问题

  1. 关于配料数量问题,买两份西瓜,当前设计不能满足

    买奶茶碰到一个人点了一杯奶茶加了十份珍珠,店员还特地打电话问是不是搞错了,结果人家还挺凶的回没搞错,又问他要不要分杯子装物料,人家也说不用!大家都一脸懵逼笑到岔气………
    这里写图片描述

  2. 某些饮料的配料不合理,茶饮料不能加西瓜,香蕉等配料,但拥有了这些配料变量

  3. 调料价格变化,会修改涉及饮料相关代码
  4. 新增加或删除配料,会修改涉及饮料相关代码

修改设计解决以上问题

引入装饰着模式,重新设计

将其分为两类,浅蓝色为我们的基本组件(我们的饮料),粉色为我们的装饰类(我们的配料)

这里写图片描述

对应代码

基础组件

Beverage

package headfirst.hd.decorator.news.component;

public abstract class Beverage {
    String description = "饮料";

    public String getDescription() {
        return description;
    }

    public abstract double cost();
}

Coffee

package headfirst.hd.decorator.news.component;

public class Coffee extends Beverage {

    public Coffee() {
        description = "咖啡";
    }

    @Override
    public double cost() {
        //饮料基础价格
        double cost = 4.0;
        return cost;
    }

}

Fruit

package headfirst.hd.decorator.news.component;

public class Fruit extends Beverage {

    public Fruit() {
        description = "果汁饮料";
    }

    @Override
    public double cost() {
        //饮料基础价格
        double cost = 2.0;
        return cost;
    }

}

H2CO3

package headfirst.hd.decorator.news.component;

public class H2CO3 extends Beverage {

    public H2CO3() {
        description = "碳酸饮料";
    }

    @Override
    public double cost() {
        //饮料基础价格
        double cost = 2.0;
        return cost;
    }

}

Tea

package headfirst.hd.decorator.news.component;

public class Tea extends Beverage {

    public Tea() {
        description = "茶饮料";
    }

    @Override
    public double cost() {
        //饮料基础价格
        double cost = 3.0;
        return cost;
    }

}
装饰者类

CondimentDecorator (配料包装类基类)

package headfirst.hd.decorator.news.decorator;

import headfirst.hd.decorator.news.component.Beverage;

public abstract class CondimentDecorator extends Beverage {

    Beverage beverage;

    public CondimentDecorator(Beverage beverage) {
        this.beverage = beverage;
    }

}

Banana

package headfirst.hd.decorator.news.decorator;

import headfirst.hd.decorator.news.component.Beverage;

public class Banana extends CondimentDecorator {

    public Banana(Beverage beverage) {
        super(beverage);
    }

    @Override
    public double cost() {
        return beverage.cost() + 2.0;
    }

}

Pearl

package headfirst.hd.decorator.news.decorator;

import headfirst.hd.decorator.news.component.Beverage;

public class Pearl extends CondimentDecorator {

    public Pearl(Beverage beverage) {
        super(beverage);
    }

    @Override
    public double cost() {
        return beverage.cost() + 1.0;
    }

}

Sugar

package headfirst.hd.decorator.news.decorator;

import headfirst.hd.decorator.news.component.Beverage;

public class Sugar extends CondimentDecorator {

    public Sugar(Beverage beverage) {
        super(beverage);
    }

    @Override
    public double cost() {
        return beverage.cost() + 1.0;
    }

}

Watermelon

package headfirst.hd.decorator.news.decorator;

import headfirst.hd.decorator.news.component.Beverage;

public class Watermelon extends CondimentDecorator {

    public Watermelon(Beverage beverage) {
        super(beverage);
    }

    @Override
    public double cost() {
        return beverage.cost() + 1.0;
    }

}

测试,买一杯果汁,加2个珍珠,加一个香蕉
TestDrive

package headfirst.hd.decorator.news.component;

import headfirst.hd.decorator.news.decorator.Banana;
import headfirst.hd.decorator.news.decorator.Pearl;

public class TestDrive {

    public static void main(String[] args) {
        //点一杯果汁
        Beverage beverage = new Fruit();
        //加两个珍珠
        beverage = new Pearl(beverage);
        beverage = new Pearl(beverage);
        //加一个香蕉
        beverage = new Banana(beverage);

        //果汁(2)+ 珍珠(1)+ 珍珠(1)+ 香蕉(2)
        System.out.println(beverage.cost());
    }

}

cost调用关系图
这里写图片描述
运行结果
这里写图片描述

回顾之前设计引发的问题

  1. 关于配料数量问题,买两份西瓜,当前设计不能满足
  2. 某些饮料的配料不合理,茶饮料不能加西瓜,香蕉等配料,但拥有了这些配料变量
  3. 调料价格变化,会修改涉及饮料相关代码
  4. 新增加或删除配料,会修改涉及饮料相关代码

似乎都已经解决啦

装饰者运用,io

这里写图片描述

在上面的关系图中可以看出:
1. InputStream是所有的输入字节流的父类,它是一个抽象类。
2. ByteArrayInputStream、StringBufferInputStream、FileInputStream是三种基本的介质流,它们分别将Byte数组、StringBuffer、和本地文件中读取数据。
3. FilterInputStream是装饰者的基类,我们可以通过继承继承增加新的装饰者

这里写图片描述

主要是重写以下两个方法
这里写图片描述

编码一个将输入流小写转换成大写的输入流UperCaseInputStream

UperCaseInputStream

package headfirst.hd.decorator.app;

import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;

public class UpperCaseInputStream extends FilterInputStream {

    public UpperCaseInputStream(InputStream inputStream) {
        super(inputStream);
    }

    @Override
    public int read() throws IOException {
        return toUpperCase(super.read());
    }

    @Override
    public int read(byte[] bytes, int offset, int len) throws IOException {
        int byteslen = super.read(bytes, offset, len);
        int end = offset + byteslen;

        for (int i = offset; i < end; i++) {
            int c = toUpperCase((char) bytes[i]);
            bytes[i] = (byte) c;
        }

        return byteslen;
    }

    //转换
    private int toUpperCase(int c) {

        // -1是文件读取的结束标志
        if (c != -1) {
            c = Character.toUpperCase(c);
        }
        return c;
    }

}

测试类TestInputStream

package headfirst.hd.decorator.app;

import java.io.InputStream;
import java.io.StringBufferInputStream;

public class TestInputStream {

    public static void main(String[] args) throws Exception {

        InputStream inputStream = new UpperCaseInputStream(new StringBufferInputStream("Do You Like Java!")); 

        //测试一
        /*int c;
        while ((c = inputStream.read()) != -1) {
            System.out.print((char)c);
        }*/

        //测试二
        byte[] bytes = new byte[1024];
        int len;
        while ((len = inputStream.read(bytes, 0, 1024)) != -1) {
            System.out.println(new String(bytes, 0, len));
        }

    }

}

测试结果
这里写图片描述

OO原则

类应该对修改关闭,扩展开发

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值