装饰者设计模式

一.装饰者模式

装饰者模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。
这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

二.示例1—-豆浆价格记账

现在有一个需求:

豆浆店的老板需要一个记账系统。该豆浆店的豆浆配料现有黑豆,糖等,但以后可能会有更多。

在我们设计的时候,如果值按照继承的思想,纯豆浆是父类,黑豆豆浆、加糖豆浆,黑豆加糖豆浆成为三个子类,那么如果以后新增了好多种配料呢,就会“类爆炸”了。

装饰者模式解决了这个问题,比如java io体系中,我们经常使用下面的例子:

OutputStream out = null;
        try {
            out = new FileOutputStream("xxx");
            BufferedOutputStream bos = new BufferedOutputStream(out);
            PrintStream ps = new PrintStream(bos);
            ps.println("xxx");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

声明的OutputStream有了输出流的基本功能后,通过后面的不断嵌套给流添加新的功能(装饰)。

那么,回到我们的需求,参考io流的设计写出我们的示例程序。

1.首先设计一个饮品接口(也可以设计成虚类),每个饮品都有价格和详细描述两个方法。

/**
 * 饮品接口,被装饰者的接口
 */
public interface Drink {

    float cost();          //计算价格

    String description();  //详细描述
}

2.然后设计我们的纯豆浆类,具体的被装饰者

/**
 * 具体的被装饰者类
 * 豆浆
 */
public class SoybeanMilk implements Drink {
    @Override
    public float cost() {
        return 10f;
    }

    @Override
    public String description() {
        return "纯豆浆";
    }
}

3.好了,我们现在有纯豆浆了,那么还需要配料。这里就是关键了,如何跟java 的io一样套来套去的呢,请看我们具体的装饰者类

/**
 * 针对饮品这个接口,相当于调料,基类常使用抽象类
 */
public abstract class Decorator implements Drink {

    private Drink drink;    //要装饰的对象

    public Decorator(Drink drink){
        this.drink=drink;
    }

    @Override
    public float cost() {
        return drink.cost();
    }

    @Override
    public String description() {
        return drink.description();
    }
}

可以看到,装饰者类Decorator和被装饰者类SoybeanMilk一样实现了Drink接口,但Decorator多了一个字段drink和一个构造方法,那么我们实现的时候就可以把被装饰的SoybeanMilk套到Decorator里面,然后再由Decorator的子类不断添加功能。

4.请看黑豆类

/**
 * 具体的装饰者类,黑豆豆浆
 */
public class BlackBeanDecorator extends Decorator {
    public BlackBeanDecorator(Drink drink) {
        super(drink);
    }

    @Override
    public float cost() {
        return super.cost() + 2.0f;//在纯豆浆的基础上加上黑豆的价格
    }

    @Override
    public String description() {
        return super.description() + "+黑豆";
    }
}

5.糖类

/**
 * 具体的装饰者类,糖豆浆
 */
public class SugarDecorator extends Decorator {
    public SugarDecorator(Drink drink) {
        super(drink);
    }

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

    @Override
    public String description() {
        return super.description() + "+糖";
    }
}

6.测试

public class Test {
    public static void main(String[] args) {
        Drink drink = new SoybeanMilk();   //老板,来杯豆浆
        SugarDecorator sugarDecorator = new SugarDecorator(drink);   //老板,加点糖
        BlackBeanDecorator blackBeanDecorator = new BlackBeanDecorator(sugarDecorator);   //老板再加点黑豆

        System.out.println("你点的豆浆是:"+blackBeanDecorator.description());
        System.out.println("一共花了"+blackBeanDecorator.cost()+"元");

    }
}

7.结果:
装饰者设计模式_第1张图片

三.示例2—-java IO体系

1.常用Io体系图
装饰者设计模式_第2张图片
2.设计基类OutputStream(只拿字节输出流做示例)

public abstract class OutputStream implements Closeable, Flushable {
    public abstract void write(int b) throws IOException;

    public void write(byte b[]) throws IOException {
        write(b, 0, b.length);
    }

    public void write(byte b[], int off, int len) throws IOException {
        ...
    }

    public void flush() throws IOException {
    }

    public void close() throws IOException {
    }
}

3.设计输出流的子类比如FileOutputStream,作为被装饰者类,如io图所示,ObjectOutputStream,PipedOutputStream等也是具体的被装饰者类。

public class FileOutputStream extends OutputStream
{
   ....
}

4.然后就需要一个装饰者类啦,虚类FilterOutputStream,所以我们几乎没用过这个类。

public class FilterOutputStream extends OutputStream {
    /**
     * The underlying output stream to be filtered.
     */
    protected OutputStream out;

    public FilterOutputStream(OutputStream out) {
        this.out = out;
    }

    public void write(int b) throws IOException {
        out.write(b);
    }

    public void write(byte b[]) throws IOException {
        write(b, 0, b.length);
    }

    public void write(byte b[], int off, int len) throws IOException {
        if ((off | len | (b.length - (len + off)) | (off + len)) < 0)
            throw new IndexOutOfBoundsException();

        for (int i = 0; i < len; i++) {
            write(b[off + i]);
        }
    }

    public void flush() throws IOException {
        out.flush();
    }

    @SuppressWarnings("try")
    public void close() throws IOException {
        try (OutputStream ostream = out) {
            flush();
        }
    }
}

FilterOutputStream继承了OutputStream接口,实现他的方法,里面也有一个OutputStream字段。之后FilterOutputStream的子类再添加新的功能就ok了。

四.总结

设计模式能大大提高效率,这是我第一次接触设计模式,理解比较浅薄。希望以后能通过做项目加深理解。

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