设计模式——装饰者模式

装饰者模式(动态添加新功能)

场景:星巴克咖啡

image-20220529011157615

装饰者模式

image-20220529110444894

装饰者模式实现

package DecoratorMode.DecoratorMode1;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
abstract class Coffee{
    protected int price;
    protected String description;
    abstract int cost();
    abstract String getDescription();
}
class LongBlackCoffee extends Coffee{

    LongBlackCoffee(){
        super(5,"黑咖啡");
    }

    @Override
    int cost() {
        return super.price;
    }

    @Override
    String getDescription() {
        return super.description;
    }
}
class ShortBlackCoffee extends Coffee{

    public ShortBlackCoffee() {
        super(4,"浓缩咖啡");
    }

    @Override
    int cost() {
        return super.price;
    }

    @Override
    String getDescription() {
        return super.description;
    }
}

abstract class Decorator extends Coffee{

    Coffee coffee;
}

class Chocolate extends Decorator{
    Chocolate(Coffee coffee){
        super.coffee=coffee;
        price=3;
        description=" 巧克力 ";
    }
    @Override
    int cost() {
        return price+coffee.cost();
    }

    @Override
    String getDescription() {
        return description+coffee.getDescription();
    }
}
class Milk extends Decorator{
    Milk(Coffee coffee){
        super.coffee=coffee;
        price=2;
        description=" 牛奶 ";
    }
    @Override
    int cost() {
        return price+coffee.cost();
    }

    @Override
    String getDescription() {
        return description+coffee.getDescription();
    }
}

public class Client {
    public static void main(String[] args) {
        Coffee coffee=new LongBlackCoffee();
        coffee=new Milk(coffee);
        coffee=new Chocolate(coffee);
        System.out.println(coffee.getDescription());
        System.out.println(coffee.cost());
    }
}

其实本质上就是一个链表,每加入一个配料(装饰者),就相当于在使用头插法在链表的头部加入了一个结点

image-20220529123838764

而计算费用的过程则是cost方法的递归调用

而如果从面向对象的角度来理解,所有的装饰者和主体都是继承了一个抽象类,还是拿咖啡举例,一开始是普通的咖啡,装饰后仍然是一杯咖啡,每一次装饰都是将一个咖啡进行包装,包装后仍然是一杯咖啡,这样就可以继续被装饰。计算费用时会从最外层开始递归调用cost方法,得到费用。

使用集合来代替这个隐式的链表

因为我们这个场景比较简单,所有装饰器对属性的处理都是一样的(做加法),如果是这样的话,我们可以使用集合类型来代替这个链表

@Data
@AllArgsConstructor
@NoArgsConstructor
abstract class Coffee{
    protected int price;
    protected String description;
}
class LongBlackCoffee extends Coffee{
    LongBlackCoffee(){
        super(5,"黑咖啡");
    }
}
class ShortBlackCoffee extends Coffee{
    public ShortBlackCoffee() {
        super(4,"浓缩咖啡");
    }
}

@Data
@AllArgsConstructor
@NoArgsConstructor
abstract class Decorator{
    protected int price;
    protected String description;
    abstract int cost(int rawCost);
}

class Milk extends Decorator{
    Milk(){
        super(3,"牛奶");
    }

    @Override
    int cost(int rawCost) {
        return rawCost+price;
    }
}
class Chocolate extends Decorator{
    Chocolate(){
        super(3,"巧克力");
    }
    @Override
    int cost(int rawCost) {
        return rawCost+price;
    }
}

class Order{
    Coffee coffee;
    List<Decorator> decorators=new LinkedList<>();
    Order(Coffee coffee){
        this.coffee=coffee;
    }
    void addDecorator(Decorator decorator){
        decorators.add(decorator);
    }
    int getCost(){
        int cost=coffee.price;
        for (Decorator decorator : decorators) {
            cost=decorator.cost(cost);
        }
        return cost;
    }
}

public class Client {
    public static void main(String[] args) {
        Order order=new Order(new LongBlackCoffee());
        order.addDecorator(new Chocolate());
        order.addDecorator(new Milk());
        System.out.println(order.getCost());
    }
}

我们直接使用List也可以达到类似的效果,并且也更好理解

对比两者

前者将前面装饰的结果作为一个整体来加上本次装饰

而后者是遍历每一个装饰者,轮流对主体进行处理

前者更加灵活,后者更加好理解。一般情况下两者方式都可以实现功能。

JDK源码在开发时,可能还没有util这个工具类,所以有时候会看到装饰者模式的影子,但在实际开发中,使用后者不仅功能可以达到,扩展性,耦合度都低于前者,开发时使用后者即可。

源码分析IO流

IO流是在JDK1.0引入的,而util包是在JDK1.2引入的,在开发IO流的时候还没有List集合,所以自然会使用我们的装饰者模式

image-20220529131737754

image-20220529134055562

我们既可以叫装饰,也可以叫它包装

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值