美文网首页
理解装饰器模式

理解装饰器模式

作者: 梦的飞翔_862e | 来源:发表于2018-11-16 18:39 被阅读0次
    概念描述

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

    场景描述

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

    设计一:

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


    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());
        }
    }
    

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

    设计三:

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



    从图中可以看出,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是抽象主体



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


    注意点

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

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

    相关文章

      网友评论

          本文标题:理解装饰器模式

          本文链接:https://www.haomeiwen.com/subject/uxipfqtx.html