设计模式 - 装饰器模式

一、基本介绍

  • 英文名:Decorator

  • 概念:动态的将新功能附加到对象上。

  • 模式类型:结构型

  • 设计原则:开闭原则(OCP)

  • 主要特点:在对象功能扩展方面,它比继承更有弹性

二、实现

需求: 下午茶:咖啡 + 调味剂,价格结算

  • 咖啡种类多,调味剂种类也多
  • 可单点咖啡,也可两者都点。且两者随意可组合(咖啡 + 多调味剂)
1、一般实现

方案一:该方案类会非常多,每增加一种咖啡或一种调味剂都需要创建很多类

  • 抽象咖啡类,所有咖啡类都实现该抽象类
  • 抽象调味剂,所有调味剂都实现该抽象类
  • 给每一种咖啡和每一种调味剂的组合都创建一个类

方案二:该方案减少了类的创建,但是增加或删除一种调味剂都需要修改已有的所有咖啡类,不易扩展

  • 抽象咖啡类,所有咖啡类都实现该抽象类
  • 抽象调味剂,所有调味剂都实现该抽象类
  • 给每一种咖啡都内置所有调味剂类
  • 使用方法判断点的是哪种组合的咖啡
2、模式实现
  • 抽象组件Component

  • 具体实现组件ConcreateComponent继承Component

  • 抽象装饰器Decorator继承Component,聚合Component(装饰器继承且聚合被装饰抽象类)

  • 具体实现装饰器ConcreteDecorator继承Decorator
    在这里插入图片描述

Ⅰ、代码
// 被装饰类 - 下午茶
public abstract class Drink {
    private String name;

    private BigDecimal price;

    // 总结算费用
    public abstract BigDecimal cost();

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public BigDecimal getPrice() {
        return price;
    }

    public void setPrice(BigDecimal price) {
        this.price = price;
    }
}

// 被装饰的某一种类抽象
public abstract class Coffee extends Drink {

    @Override
    public BigDecimal cost() {
        return super.getPrice();
    }
}

// 被装饰的某一种类的具体实现
public class Latte extends Coffee {

    // 可使用super,也可直接调用父类方法
    public Latte() {
        super.setName("拿铁");
        setPrice(new BigDecimal("15.69"));
    }
}

// 被装饰的某一种类的具体实现
public class Americano extends Coffee {

    public Americano() {
        setName("美式");
        setPrice(new BigDecimal("23.99"));
    }
}

// 装饰器类继承且聚合被装饰抽象类
public class Decorator extends Drink {
    private Drink drink;

    public Decorator(Drink drink) {
        this.drink = drink;
    }

    /**
     * @Description 递归计算费用(注入进的饮料价格 + 本身装饰器(调味品)的的价格)
     * this.drink是构造器传入的对象
     */
    @Override
    public BigDecimal cost() {
        return this.drink.cost().add(this.getPrice());
    }

    @Override
    public String getName() {
        return this.drink.getName() + " " + super.getName();
    }
}

// 具体装饰类继承装饰器类
public class Milk extends Decorator {

    public Milk(Drink drink) {
        super(drink);
        super.setName("牛奶");
        setPrice(new BigDecimal("1.25"));
    }
}

// 具体装饰类继承装饰器类
public class Sugar extends Decorator {

    public Sugar(Drink drink) {
        super(drink);
        super.setName("糖");
        setPrice(new BigDecimal("0.19"));
    }
}

public class Test {
    public static void main(String[] args) {
        Drink drink = new Latte();
        BigDecimal cost = drink.cost();
        System.out.println(drink.getName() + ": " + cost + "元");

        // 装饰者 装饰 被装饰抽象类的具体实现
        drink = new Milk(drink);
        cost = drink.cost();
        System.out.println(drink.getName() + ": " + cost + "元");

        drink = new Sugar(drink);
        cost = drink.cost();
        System.out.println(drink.getName() + ": " + cost + "元");
    }
}
Ⅱ、优点
  • 装饰类和被装饰类可以独立发展,而不会相互耦合
  • 继承关系的一个替代方案,不管装饰多少层,返回的对象还是原来的对象
  • 可以动态地扩展一个实现类的功能
Ⅲ、缺点
  • 多层的装饰是比较复杂的。就像剥洋葱一样,剥到了最后才发现是最里层的装饰出现了问题,想象一下工作量吧,因此,尽量减少装饰类的数量,以便降低系统的复杂度

三、使用场景

  • 需要扩展一个类的功能,或给一个类增加附加功能
  • 需要动态地给一个对象增加功能,这些功能可以再动态地撤销
  • 需要为一批的兄弟类进行改装或加装功能,当然是首选装饰模式
1、常见应用场景
Ⅰ、IO流的FilterInputStream
  • FilterInputStream继承InputStream抽象类,且聚合InputStream被装饰抽象类,即FilterInputStream充当装饰器
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值