设计模式之装饰者模式

目录

一、简介

二、范例:咖啡店

三、优化方案:实例变量和继承

四、优化方案:装饰者模式

4.1、做法图解:

 4.2、代码实现

五、Java中的装饰者模式


一、简介

装饰器模式(Decorator
Pattern)
 :允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。

这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。


二、范例:咖啡店

刚开始时,咖啡店的程序设计是:

  • 一个咖啡饮料的父类 Beverage,抽象类,店里的所有饮料都必须继承此父类
  • 不同种类的咖啡饮料都是一个类(都需要继承 Beverage类)

在这里插入图片描述

 带来的问题:

购买咖啡饮料时,客户可以要求加入不同中类的配料,如:摩卡、奶泡…

此时的咖啡店的程序设计是:

在这里插入图片描述


三、优化方案:实例变量和继承

Beverage类优化:

Beverage类中新增表示各种调料的实例变量

在这里插入图片描述

 咖啡饮料类:

在这里插入图片描述

 带来的问题:

  • 调料价格的改变需要修改代码
  • 新增调料需要改变Beverage类的 cost()方法

设计原则:类应该对扩展开放,对修改关闭


四、优化方案:装饰者模式

以咖啡饮料为主体,然后在运行时以调料来装饰(decorate)咖啡饮料。比如,如果顾客想要摩卡和奶泡深培咖啡,那么,做法是:

  1. 获取一个深培咖啡(DarkRoast)对象
  2. 以摩卡(Mocha)调料对象来装饰它
  3. 以奶泡(Whip)调料对象来装饰它
  4. 调用cost()方法,并依赖委托(delegate)将调料的价格加上去

4.1、做法图解:

  1. 获取一个深培咖啡(DarkRoast)对象
    在这里插入图片描述
  2. 顾客想要摩卡(Mocha)调料,所以建立一个Mocha对象,并用它将DarkRoast对象包(wrap)起来
    在这里插入图片描述
  3. 顾客想要奶泡(Whip),所以建立一个Whip装饰者,并将它Mocha对象包起来
    在这里插入图片描述
  4. 计算总价钱,调用最外层的装饰者(Whip)的cost()方法就可以计算出总价钱。Whip的cost()方法会委托它装饰的对象,即Mocha,计算出价钱,然后再加上奶泡的价钱
    在这里插入图片描述

 4.2、代码实现

 Beverage类:

package com.kgf.headFirst.decorator;

/**
 * 咖啡饮料父类
 * @author kgf
 * @date 2023/6/11 22:19
 */
public abstract class Beverage {

    String description = "咖啡饮料父类";

    public String getDescription() {
        return description;
    }

    public abstract double cost();

}

 咖啡饮料类:

package com.kgf.headFirst.decorator;

/**
 * 咖啡饮料类:
 * @author kgf
 * @date 2023/6/11 22:20
 */
public class Espresso extends Beverage{

    public Espresso() {
        description = "浓缩咖啡";
    }

    @Override
    public double cost() {
        return 1.99;
    }
}
package com.kgf.headFirst.decorator;

/**
 * 混搭咖啡
 * @author kgf
 * @date 2023/6/11 22:21
 */
public class HouseBlend extends Beverage{

    public HouseBlend() {
        description = "混搭咖啡";
    }

    @Override
    public double cost() {
        return 1.5;
    }
}

调料类:

package com.kgf.headFirst.decorator;

/**
 * 调料类
 * @author kgf
 * @date 2023/6/11 22:23
 */
public abstract class CondimentDecorate extends Beverage{

    @Override
    public abstract String getDescription();
}
package com.kgf.headFirst.decorator;

/**
 * 摩卡
 * @author kgf
 * @date 2023/6/11 22:24
 */
public class Mocha extends CondimentDecorate{

    Beverage beverage;

    /***
     * 让Mocha对象能够引用一个Beverage
     * 用一个实例变量记录饮料,即被装饰者
     *  让被装饰者(饮料)被记录到实例变量中(此处做法是:把饮料作为构造器的参数,再由构造器将此饮料记录在实例变量中)
     * @param beverage
     */
    public Mocha(Beverage beverage) {
        this.beverage = beverage;
    }

    @Override
    public double cost() {
        // 计算带Mocha的咖啡饮料的价钱:Mocha的价钱 + 咖啡饮料的价钱
        return 0.5 + beverage.cost();
    }

    @Override
    public String getDescription() {
        return beverage.getDescription() + ",摩卡";
    }
}
package com.kgf.headFirst.decorator;

/**
 * 调料:奶泡
 * @author kgf
 * @date 2023/6/11 22:26
 */
public class Whip extends CondimentDecorate{

    Beverage beverage;

    public Whip(Beverage beverage) {
        this.beverage = beverage;
    }

    @Override
    public double cost() {
        return 0.8 + beverage.cost();
    }

    @Override
    public String getDescription() {
        return beverage.getDescription() + ",奶泡";
    }
}

测试:

package com.kgf.headFirst.decorator;

/**
 * @author kgf
 * @date 2023/6/11 22:33
 */
public class Test {

    public static void main(String[] args) {
        Beverage espresso = new Espresso();
        //咖啡饮料:浓缩咖啡,价钱:1.99
        System.out.println("咖啡饮料:" + espresso.getDescription() + "," + "价钱:" + espresso.cost());

        Beverage houseBlend = new HouseBlend();
        // 加摩卡
        houseBlend = new Mocha(houseBlend);
        // 加奶泡
        houseBlend = new Whip(houseBlend);
        //咖啡饮料:混搭咖啡,摩卡,奶泡,价钱:2.8
        System.out.println("咖啡饮料:" + houseBlend.getDescription() + "," + "价钱:" + houseBlend.cost());

    }

}

总结:

在这里插入图片描述


五、Java中的装饰者模式

IO流API:

在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值