美文网首页
装饰者模式

装饰者模式

作者: 寂静的春天1988 | 来源:发表于2020-08-27 08:56 被阅读0次

    给对象增强的手段
    1、继承

    • 被增强的对象是固定的
    • 增强的内容也是固定的
      2、装饰者模式
    • 被增强的对象是可以切换的
    • 增强的内容是固定的
      3、动态代理
    • 被增强的内容是可以切换的
    • 增强的内容也可以切换

    星巴兹公司原先的代码


    image.png

    新的需求:购买咖啡时,可以要求在其中加入任何调料,例如:奶茶,牛奶,豆浆。星巴兹根据业务需求会计算相应的费用。这就要求订单系统必须考虑到这些调料的部分。

    第一个设计.png

    这里设计非常繁琐:比如要算一杯 HouseBlend的价格,总共就以下几个类
    HouseBlend&&奶茶
    HouseBlend&&牛奶
    HouseBlend&&豆浆
    ...等等
    这样设计需要算出每一种咖啡和配料的组合的可能,类的创建非常之多。而且增加一种调料增加的类也是非常爆炸的。

    这里可以看出继承的局限性,只能增强一个对象。

    第二个设计.png
    package com.yl;
    public class Beverage {
        protected String description;//饮料简介
        
        protected boolean milk=false;//是否有牛奶
        
        protected boolean soy=false;//是否有豆浆
        
        protected boolean cocha=false;//是否有摩卡
        
        protected boolean whip=false;//是否有奶泡
        
        protected double milkCost=1.01;//牛奶价格
        
        protected double soyCost=1.03;//豆浆价格
        
        protected double cochaCost=2.23;//摩卡价格
        
        protected double whipCost=0.89;//奶泡价格
        
        
        public String getDescription() {
            return description;
        }
    
    
        public void setDescription(String description) {
            this.description = description;
        }
    
    
        public boolean hasMilk() {
            return milk;
        }
    
    
        public void setMilk(boolean milk) {
            this.milk = milk;
        }
    
    
        public boolean hasSoy() {
            return soy;
        }
    
    
        public void setSoy(boolean soy) {
            this.soy = soy;
        }
    
    
        public boolean hasCocha() {
            return cocha;
        }
    
    
        public void setCocha(boolean cocha) {
            this.cocha = cocha;
        }
    
    
        public boolean hasWhip() {
            return whip;
        }
    
    
        public void setWhip(boolean whip) {
            this.whip = whip;
        }
        
        
    
    
        public double getCochaCost() {
            return cochaCost;
        }
    
    
        public void setCochaCost(double cochaCost) {
            this.cochaCost = cochaCost;
        }
    
    
        public double getWhipCost() {
            return whipCost;
        }
    
    
        public void setWhipCost(double whipCost) {
            this.whipCost = whipCost;
        }
    
    
       
        /**
         * 计算调料价格
         * @return
         */
        public double cost(){
            
            double condiments=0.0;
            if(hasMilk()){//是否需要牛奶
                condiments+=milkCost;
            }
            if(hasSoy()){//是否需要豆浆
                condiments+=soyCost;
            }
            if(hasCocha()){//是否需要摩卡
                condiments+=cochaCost;
            }
            if(hasWhip()){//是否需要奶泡
                condiments+=whipCost;
            }
            return condiments;
        }
    
    }
    
    public class DarkRoast extends Beverage {
        public DarkRoast(){
            description="Most Excellent Dark Roast!";
        }
        public double cost(){
            return 1.99+super.cost();
        }
    }
    

    这样会存在几个问题:
    1、增加调料或者减少调料或者价格变化,都需要该基类Beverage的代码。违反了开放-关闭原则。一旦基类经过测试上线基本是不能修改的,因为影响到了太多的子类。
    2、如果加两分调料也是没办法计算价格的。

    使用装饰者模式

    public abstract class Beverage {
        protected String description="Unknown";//饮料简介
        
        /**
         * 计算价格
         * @return
         */
        public abstract double cost();
    
        public String getDescription() {
            return description;
        }
    }
    
    
    public class DarkRoast extends Beverage {
        
        public DarkRoast(){
            description="Most Excellent Dark Roast!";
        }
        public double cost(){
            return 1.99;
        }
        
    }
    
    public abstract class CondimentDecorator extends Beverage {
    
        public abstract String getDescription();
    
    }
    
    /**
     * 牛奶装饰类
     * @author user
     *
     */
    public class Milk extends CondimentDecorator {
        
        private Beverage beverage;
        
        public Milk(Beverage beverage) {
            this.beverage=beverage;
        }
        
        @Override
        public String getDescription() {
            return beverage.getDescription()+",milk";
        }
    
        @Override
        public double cost() {
            return beverage.cost()+0.2;
        }
    
    }
    
    /**
     * 奶泡装饰类
     * @author user
     *
     */
    public class Whip extends CondimentDecorator {
        
        private Beverage beverage;
        
        public Whip(Beverage beverage) {
            this.beverage=beverage;
        }
        
        @Override
        public String getDescription() {
            return beverage.getDescription()+",Whip";
        }
    
        @Override
        public double cost() {
            return beverage.cost()+0.5;
        }
    
    }
    

    装饰者模式的缺点:
    1、如果代码中有针对类型的对象类型做一些事情,会失败。包装类虽然具有被包装类的所有属性和方法,但是类型变了。

            Beverage beverage=new DarkRoast();// 1.99
            beverage=new Milk(beverage);// 0.2
            beverage=new Milk(beverage);// 0.2
            beverage=new Whip(beverage);// 0.5
            System.out.println(beverage.getDescription()+":"+beverage.cost());
            if(beverage instanceof DarkRoast) {
                System.out.println("打八折:"+beverage.cost()*0.8);
            }
    

    2、java io流当中就使用了大量的装饰者模式,但是会发现生成了大量的小类,使得代码复杂度变高。

    相关文章

      网友评论

          本文标题:装饰者模式

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