理解装饰器模式

概念描述

装饰器模式是一种结构型模式,它是对现有对象的一个包装,然后在包装类中加入新的功能。

场景描述

考虑这样一个场景:咖啡店中目前有咖啡,比如espresso,americano,decaf,客人根据自己的喜好,可以选择加糖,加奶或者两者都加,也可以什么都不加,当然,根据加入原料的不同价格也不相同。

设计一:

以直观的想法去设计这样一个结构,应该是


理解装饰器模式_第1张图片
Coffee.java
public class Coffee {
    private String description;
    private double cost;
    public Coffee(String description, double cost) {
        this.description = description;
        this.cost = cost;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }
    public double getCost() {
        return cost;
    }
    public void setCost(double cost) {
        this.cost = cost;
    }
}
Americano.java
public class Americano extends  Coffee{
    public Americano(){
        super("americano",12);
    }
}
SugarAmericano.java
public class SugarAmericano  extends Coffee{

    public SugarAmericano(){
        super("sugarAmericano",15);
    }
}

上面的结构一个很明显的缺陷是,咖啡和配料有很多种组合,需要将每一种组合都定义为一个类,这样的结构会变的庞大而不好维护。

设计二:

第二种改进的方式,可以将配料定义在超类中,在子类中通过条件判断语句,来组成不同的组合

Coffee.java
public class Coffee {
    private String description;
    private double cost;

    private boolean sugar;
    private boolean milk;

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public double getCost() {
        return cost;
    }

    public void setCost(double cost) {
        this.cost = cost;
    }

    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;
    }
}
Americano.java
public class Americano extends Coffee {
    public Americano(){
        super();
    }

    @Override
    public String getDescription() {
        StringBuffer desc= new StringBuffer();
        if(isSugar()){
            desc.append("add sugar,");
        }
        if(isMilk()){
            desc.append("add milk ,");
        }
        desc.append("americano");
       return desc.toString();
    }



    @Override
    public double getCost() {
       double cost= 3.0;
       if(isMilk()){
           cost+=1;
       }
       if(isSugar()){
           cost+=3;
       }

       return cost;
    }
}
TestApp.java
public class TestApp {

    public static void main(String[] args) {
        Coffee coffee = new Americano();
        coffee.setMilk(true);
        System.out.println(coffee.getDescription());
        System.out.println(coffee.getCost());
        coffee.setSugar(true);
        System.out.println(coffee.getDescription());
        System.out.println(coffee.getCost());
    }
}

设计二中的结构比第一种结构简单很多,但是如果新增一种配料,父类和子类都需要做相应的修改,这违反了开放封闭原则。

设计三:

使用装饰器设计模式后,项目结构调整为:


理解装饰器模式_第2张图片

从图中可以看出,CoffeeDecorator是一个抽象装饰器,需要继承和引用抽象主体类。因为装饰器的本体仍然是Coffee

Coffee.java
public abstract class Coffee {
    private String description;
    private double cost;
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }

    public  double getCost(){
        return this.cost;
    }

    public void setCost(double cost) {
        this.cost = cost;
    }
}
//具体的主体Americano 
public class Americano extends Coffee {

    public Americano(){
        super();
        super.setCost(3);
        super.setDescription("americano");
    }
}
//具体的主体
public class Espresso extends Coffee {

    public Espresso(){
        super();
        super.setCost(14);
        super.setDescription("espresso");
    }
}
//抽象装饰器
public abstract class CoffeeDecorator extends Coffee {

    private Coffee coffee;

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

    public double getCost(){
        return super.getCost()+coffee.getCost();
    }

    public String getDescription(){
        return super.getDescription()+","+coffee.getDescription();
    }
}
//具体装饰器
public class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee coffee){
        super(coffee);
        super.setCost(5);
        super.setDescription("add milk");
    }
}
public class SugarDecorator extends CoffeeDecorator{

    public SugarDecorator(Coffee coffee){
        super(coffee);
        super.setCost(2);
        super.setDescription(" add sugar");

    }


}
//TestApp.java
public class TestApp {
    public static void main(String[] args) {
        //单品
        Coffee americano = new Americano();
        System.out.println("americano:"+americano.getCost());
        System.out.println("americano:"+americano.getDescription());
        //加入糖
        americano = new SugarDecorator(americano);
        System.out.println("sugar americano:"+americano.getCost());
        System.out.println("sugar americano:"+americano.getDescription());
        //再加入牛奶
        americano = new MilkDecorator(americano);
        System.out.println("sugar milk americano:"+americano.getCost());
        System.out.println("sugar milk  americano:"+americano.getDescription());
    }
}

java中的装饰器:

Java中的流是典型的装饰器模式,以输入流为例,FileInputStream是具体的主体,InputStream是抽象主体


理解装饰器模式_第3张图片

同样的具体实体还有ByteArrayInputStream和StringBufferInputStream 。
输入流的抽象装饰器是FilterInputStream ,具体装饰器如BufferedInputStream,DataInputStream等


理解装饰器模式_第4张图片
注意点

软件设计的原则:对修改封闭,对扩展开放
装饰器的优点:可以动态扩展一个对象的功能,比如咖啡Americano单品, 可以加糖,可以加奶,可以两者都加,这个过程,可以在运行时决定如何自由组合。
缺点:多层继承,结构稍复杂。

代码实例在https://github.com/jxl198/designPattern/tree/master/decorator

你可能感兴趣的:(理解装饰器模式)