• 装饰器模式


    基本介绍

    装饰器模式意图为一个对象扩展新的功能,且不改变原有的结构,装饰器模式属于结构型设计模式

    一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀

    使用场景

    • 扩展一个类的功能
    • 动态增加功能,动态撤销

     

    假设有一家咖啡公司,姑且咱就叫怪兽咖啡吧,该咖啡公司是以扩展速度最快而闻名的咖啡公司(像瑞幸咖啡一样),但是最近由于扩展速度太快,它们想重新设计一套订单系统,以满足它们现在的饮料需求。

    他们最初始的设计如下:

     

    然鹅用户在购买咖啡时,通常会添加一些调料,例如:摩卡、豆浆、奶泡等等。怪兽咖啡并根据业务去计算相应的总价,这就要求咖啡公司在设计订单时需要考虑这些调料的部分。然后就设计出这么一套庞杂的系统,因为奶茶种类太多,调料太多。种类*调料 = 类爆炸,实在太疯狂了

     

    这么设计的问题显而易见

    • 调料价格变化时,需要更改现有代码
    • 出现新的调料,需要添加新的方法,并改动超类中的cost()方法
    • 以后开发新的饮料,对于这些饮料,某些调料并不适合,但是这个设计中,子类仍需继承那些不需要的方法

     

    装饰器模式

    从上述的设计方案来看,这显然并不是一个聪明的结果,因为会遇到 类爆炸、设计过于冗余,以及基类加入的新功能并不一定适用于所有子类

     

    所以我们要考虑换一种方式,设想一下 我们能不能 以饮料为红花,用调料作为 绿叶 装饰它

    比如,客户想要 摩卡和奶泡 搭配黑莓咖啡(口味独特),那么,我们怎么做呢?

    • 拿黑莓咖啡(DarkRoast)作为对象
    • 用摩卡(Mocha)对象装饰它
    • 用奶泡(Whip)对象装饰它
    • 调用 cost() 方法,并通过依赖将调料价格和摩卡价格想加

     

     

    上图详细的介绍了,装饰模式的总体过程

     

    上图为装饰器模式的结构类图以及各个类的作用说明

     

    好,下面我们详细介绍订单系统的正确设计方案

    1、我们先设计饮料组件

    /**
     * 创建一个饮料抽象类
     */
    public abstract class Beverage {
    
        String description = "UnKnown Beverage";
    
        public String getDescription() {
            return description;
        }
    
        public abstract Double cost();
    
    }
    

     

    2、假设目前店铺中,有 综合咖啡、浓缩咖啡、黑莓

    public class HouseBlend extends Beverage {
    
        public HouseBlend() {
            description = "综合咖啡";
        }
    
        @Override
        public Double cost() {
            return 23.2;
        }
    }
    
    public class Expresso extends Beverage{
    
        public Expresso(){
            description = "浓缩咖啡";
        }
    
        @Override
        public Double cost() {
            return 19.9;
        }
    }
    
    public class DarkRoast extends Beverage {
    
        public DarkRoast() {
            description = "黑莓咖啡";
        }
    
        @Override
        public Double cost() {
            return 21.8;
        }
    
    }
    

     

    3、下面我们实现调料类的抽象类,也就是装饰者类

    /**
     * 调料抽象类
     */
    public abstract class Condiment extends Beverage {
    
        Beverage beverage;
    
        Condiment(Beverage decoratedBeverage){
            this.beverage = decoratedBeverage;
        }
    
        public abstract String getDescription();
    
    }
    

     

    4、 然后我们再实现相应的 Mocha、Whip、Soy 的调料代码

    /**
     * 摩卡
     */
    public class Mocha extends Condiment {
    
    
        public Mocha(Beverage beverage) {
            super(beverage);
        }
    
        @Override
        public String getDescription() {
            return beverage.getDescription() + "【摩卡】";
        }
    
        @Override
        public Double cost() {
            return new BigDecimal(beverage.cost().toString()).add(new BigDecimal(2.2)).doubleValue();
        }
    }
    
    /**
     * 豆浆
     */
    public class Soy extends Condiment {
    
        public Soy(Beverage beverage) {
            super(beverage);
        }
    
        @Override
        public String getDescription(){
            return beverage.getDescription() + "【豆浆】";
        }
    
        @Override
        public Double cost() {
            return new BigDecimal(beverage.cost().toString()).add(new BigDecimal(3.6)).doubleValue();
        }
    }
    
    /**
     *  奶泡
     */
    public class Whip extends Condiment {
    
        public Whip(Beverage beverage){
            super(beverage);
        }
    
        @Override
        public String getDescription() {
            return beverage.getDescription() + "【奶泡】";
        }
    
        @Override
        public Double cost() {
            return new BigDecimal(beverage.cost().toString()).add(new BigDecimal(2.7)).doubleValue();
        }
    }
    

     

    好了,参考装饰者模式,订单模块的基本实现已经基本完成。下面是测试代码

    public class Client {
        public static void main(String[] args) {
            //一杯DarkRoast 不需要调料
            Beverage darkRoast = new DarkRoast();
            System.out.println(darkRoast.getDescription() + "," + darkRoast.cost());
    
            //再点一个浓缩咖啡 加 双倍摩卡 一份奶泡
            Beverage beverage = new Expresso();
            beverage = new Mocha(beverage);
            beverage = new Mocha(beverage);
            beverage = new Whip(beverage);
            System.out.println(beverage.getDescription() + "," + beverage.cost());
        }
    }
    


     

    IO体系中的装饰器


    由图可见,InputStream就是装饰者模式中的超类(Component),
    ByteArrayInputStream,FileInputStream相当于 被装饰者(ConcreteComponent),这些类都提供了最基本的字节读取功能。
    而另外一个和这两个类是同一级的类FilterInputStream 即为 抽象装饰者(AbstarctDecorator)
    BufferedInputStream,DataInputStream,PushbackInputStream(都继承了FilterInputStream类),它们为 装饰者(Decorator),在原有基础功能上都实现了功能的扩展和增强。
     
    例:用BufferedInputStream 装饰 FileInputStream,和上面Mocha(摩卡) 装饰 DarkRoast(黑莓)如出一辙

    File file = new File ("hello.txt"); 
    FileInputStream in=new FileInputStream(file); 
    BufferedInputStream inBuffered=new BufferedInputStream (in); 
    
  • 相关阅读:
    获得二进制有多少个1
    读取txt数据
    int最大值
    oracle——数据表的相关操作——约束——各种约束详解
    oracle——数据表的相关操作——转移表空间
    oracle——数据表的相关操作——删除数据表
    oracle——数据表的数据查询——oracle高级函数
    oracle——数据表的相关操作——更新数据——update操作
    oracle——数据表的数据查询——oracle中的特殊表达式between and、in、like、is null、exists、all、some、any等
    oracle——数据表的数据查询——distinct 关键字、group by 字句、having子句
  • 原文地址:https://www.cnblogs.com/dwlovelife/p/13326739.html
Copyright © 2020-2023  润新知