设计模式之装饰着模式

1. 装饰者模式

小王家里新开了一家咖啡店,咖啡店里面有两种咖啡:白咖啡和黑咖啡。Java代码如下:

public abstract class Coffee {
    private String description; //咖啡简介

    public Coffee(String description) {
        this.description = description;
    }

    public String getDescription() {
        return description;
    }

    public abstract double cost();

    public static void main(String[] args) {
        Coffee c1 = new BlackCoffee("black");
        Coffee c2 = new WhiteCoffee("white");

        System.out.println("c1: " + c1.getDescription() + "  cost: " + c1.cost());
        System.out.println("c2: " + c2.getDescription() + "  cost: " + c2.cost());
    }

}

class BlackCoffee extends Coffee{

    public BlackCoffee(String description) {
        super(description);
    }

    @Override
    public double cost() {
        return 5.0;
    }
}

class WhiteCoffee extends Coffee{

    public WhiteCoffee(String description) {
        super(description);
    }

    @Override
    public double cost() {
        return 6.0;
    }
}

随着咖啡店的规模越来越大,咖啡店顾客的要求越来越高,有些顾客要求加牛奶,有些要求加糖。这是要如何修改Java代码呢?

public abstract Coffee{}
class WhiteCoffee extends Coffee{}
class BlackCoffee extends Coffee{}
class MilkWhiteCoffee extends WhiteCoffee{}
class SugarWhiteCoffee extends WhiteCoffee{}
class MilkBlackCoffee extends WhiteCoffee{}
class SugarBlackCoffee extends WhiteCoffee{}

在这里插入图片描述
上面这种方法看似简单直接,但如果又有一些顾客要求加牛奶和糖呢?某一天咖啡店要推出新品灰咖啡呢?那么我们需要写的代码量将会非常的大。
另外一种解决方案:

package designpattern.decorator;

public abstract class Coffee2 {
    private String description;
    private boolean sugar;
    private boolean milk;

    public Coffee2(String description) {
        this.description = description;
    }

    public boolean isSugar() {
        return sugar;
    }

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

    public boolean isMilk() {
        return milk;
    }

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

    public String getDescription() {
        return description;
    }

    public abstract double cost();
}

class WhiteCoffee2 extends Coffee2  {

    public WhiteCoffee2(String description) {
        super(description);
    }

    @Override
    public double cost() {
        return 5.0;
    }
}

class BlackCoffee2 extends Coffee2  {

    public BlackCoffee2(String description) {
        super(description);
    }

    @Override
    public double cost() {
        return 6.0;
    }
}

这样子,我们如果有顾客需要新配料,那么我们只需要在Coffee2增加新变量和setter/getter即可。推出新品,则创建要给新的类来继承Coffee2。这种方法比上一种方便很多,但也存在一些弊端:

  1. 如果有新配料,那么我们必须修改Coffee2
  2. 如果有顾客需要两份糖,如何表示?
  3. 其它。。。。

所以,真正解决办法的设计模式是:装饰者模式:
在这里插入图片描述
左边的是Coffee的实体类,右边是装饰类,即配料。每一个装饰类中都有一个实体类实例变量,表示,这个类型的实体(咖啡)被这个装饰类装饰(添加配料)。为什么在需要CondimentDecorator?并且getDescription()为abstract?我们慢慢往下看。
首先,我们来实现一下这个装饰者模式:

package designpattern.decorator;

public abstract class Coffee {
    String description = "Unknow Type"; //咖啡简介

    public String getDescription() {
        return description;
    }

    public abstract double cost();


    public static void main(String[] args) {
        Coffee c1 = new WhiteCoffee("white coffee");//白咖啡
        c1 = new Milk(c1);//白咖啡加奶
        c1 = new Sugar(c1);//白咖啡加糖加奶
        System.out.println(c1.getDescription() + "  ¥" + c1.cost());
    }



}

class BlackCoffee extends Coffee{

    public BlackCoffee(String description) {
        this.description = description;
    }

    @Override
    public double cost() {
        return 5.0;
    }
}

class WhiteCoffee extends Coffee{

    public WhiteCoffee(String description) {
        this.description = description;
    }

    @Override
    public double cost() {
        return 6.0;
    }
}

abstract class CondimentDecorator extends Coffee {

    Coffee coffee;

    public abstract String getDescription();
}

class Milk extends CondimentDecorator {

    public Milk(Coffee coffee) {
        this.coffee = coffee;
    }

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

    @Override
    public String getDescription() {
        return coffee.getDescription() + " " + ", milk ";
    }
}

class Sugar extends CondimentDecorator {

    public Sugar(Coffee coffee) {
        this.coffee = coffee;
    }

    @Override
    public double cost() {
        return coffee.cost() + 0.5;
    }

    @Override
    public String getDescription() {
        return coffee.getDescription() + ", sugar";
    }
}
2. 使用装饰者模式,自己实现一个LowerCaseIO
import java.io.*;

/**
 * FilterInputStream是abstract decorator
 * LowerCaseIO是concrete decorator
 */
public class LowerCaseIO extends FilterInputStream {
    /**
	 * 调用父类构造方法。InputStream作为符类的成员变量,我们需要调用父类构造函数来初始化它。
     * Creates a <code>FilterInputStream</code>
     * by assigning the  argument <code>in</code>
     * to the field <code>this.in</code> so as
     * to remember it for later use.
     *
     * @param in the underlying input stream, or <code>null</code> if
     *           this instance is to be created without an underlying stream.
     */
    protected LowerCaseIO(InputStream in) {
        super(in);
    }

    public int read() throws IOException {
        int c = super.read();
        return c == -1 ? c : Character.toLowerCase((char)c);
    }

    public int read(byte[] bytes, int off, int len) throws IOException {
        int result = super.read(bytes, off, len);

        for(int i = off; i < len + off; i++) {
            bytes[i] = (byte) Character.toLowerCase((char)bytes[i]);
        }
        return result;
    }

    public static void main(String[] args) throws IOException {
        InputStream stream = new LowerCaseIO(new BufferedInputStream(new FileInputStream("D:\\test.txt")));
        byte[] bytes = new byte[10];
        int i = stream.read(bytes, 0, 10);
        System.out.println("读取了" + i + "个字节");
        for(byte b: bytes) {
            System.out.print((char)b);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值