架构师内功心法,有重构项目经验必备的装饰者模式详解

1、装饰者模式的应用场景

在咱们的生活中好比给煎饼加个鸡蛋,给蛋糕加上一些水果,给房子装修等。为对象扩展一些额外对象的职责。装饰者模式(Decorator Pattern)是指在不改变原有对象的基础之上,提供了比继承更有弹性的替代方案(扩展原有对象的功能)。 缓存

装饰者模式使用于如下几种场景:ide

  • 用于扩展一个类的功能或给一个类添加附加职责;
  • 动态的给一个对象添加功能,这些功能能够动态的撤销。

1.1 🌮 早餐吃煎饼的装饰者模式

在北京早上通勤上班的同窗们,都有吃过路边摊的煎饼吧。买煎饼的时候可让他给你加个鸡蛋,也能够加香肠,还能够加辣条等。下面咱们用代码来实现下这个生活场景的案例,首先建立一个煎饼 BatterCake 类:测试

public class BatterCake {

    protected String getMsg() {
        return "煎饼";
    }

    protected BigDecimal getPrice() {
        return new BigDecimal(6.00);
    }

}

再建立一个加鸡蛋的煎饼 BatterCakeWithEgg 类:this

public class BatterCakeWithEgg extends BatterCake {

    @Override
    protected String getMsg() {
        return super.getMsg() + "加了1个鸡蛋";
    }

    protected BigDecimal getPrice() {
        return new BigDecimal(6.00).add(new BigDecimal(1.00));
    }

}

再建立一个既加鸡蛋又加香肠的 BattercakeWithEggAndSausage 类:code

public class BatterCakeWithEggAndSausage extends BatterCakeWithEgg {

    @Override
    protected String getMsg() {
        return super.getMsg() + "又加了1根香肠";
    }

    @Override
    protected BigDecimal getPrice() {
        return super.getPrice().add(new BigDecimal(2.00));
    }
}

测试main方法:对象

public static void main(String[] args) {
    Battercake battercake = new Battercake();
    System.out.println(battercake.getMsg() + ",总价格:" + battercake.getPrice().doubleValue());
    Battercake battercakeWithEgg = new BattercakeWithEgg();
    System.out.println(battercakeWithEgg.getMsg() + ",总价格:" + battercakeWithEgg.getPrice().doubleValue());
    Battercake battercakeWithEggAndSausage = new BattercakeWithEggAndSausage();
    System.out.println(battercakeWithEggAndSausage.getMsg() + ",总价格:" +
            battercakeWithEggAndSausage.getPrice().doubleValue());
}

运行结果:blog

上面的程序运行结果没有问题,若是须要加2个鸡蛋2个香肠,那么如今实现的方法是没法知足要求的,也没法计算出价格,除非再定制一个类来实现。若是须要一直变显然不科学。下面咱们就用装饰者模式来解决以上问题,首先建立一个抽象的 Battercake 类:继承

public abstract class Battercake {

    protected abstract String getMsg();

    protected abstract BigDecimal getPrice();

}

建立一个基本的煎饼(或者叫基础套餐)BaseBattercake 类:事务

public class BaseBattercake extends Battercake {
    @Override
    protected String getMsg() {
        return "煎饼";
    }

    @Override
    protected BigDecimal getPrice() {
        return new BigDecimal(6.00);
    }
}

再建立一个扩展套餐的抽象装饰者 BattercakeDecotator 类:ci

public class BattercakeDecorator extends BaseBattercake {

    private Battercake battercake;

    public BattercakeDecorator(Battercake battercake) {
        this.battercake = battercake;
    }

    @Override
    protected String getMsg() {
        return this.battercake.getMsg();
    }

    @Override
    protected BigDecimal getPrice() {
        return this.battercake.getPrice();
    }
}

建立鸡蛋装饰者 EggDecorator 类:

public class EggDecorator extends BattercakeDecorator {
    public EggDecorator(Battercake battercake) {
        super(battercake);
    }

    @Override
    protected String getMsg() {
        return super.getMsg() + "加1个鸡蛋";
    }

    @Override
    protected BigDecimal getPrice() {
        return super.getPrice().add(new BigDecimal(1.00));
    }
}

建立香肠装饰者 SausageDecorator 类:

public class SausageDecorator extends BattercakeDecorator {
    public SausageDecorator(Battercake battercake) {
        super(battercake);
    }

    @Override
    protected String getMsg() {
        return super.getMsg() + "加1根香肠";
    }

    @Override
    protected BigDecimal getPrice() {
        return super.getPrice().add(new BigDecimal(2.00));
    }
}

测试代码:

public static void main(String[] args) { Battercake battercake; //路边摊买一个煎饼 battercake = new BaseBattercake(); //煎饼有点小,想再加一个鸡蛋 battercake = new EggDecorator(battercake); //再加一个鸡蛋 battercake = new EggDecorator(battercake); //很饿,再加根香肠 battercake = new SausageDecorator(battercake); System.out.println(battercake.getMsg() + ",总价:" + battercake.getPrice().doubleValue()); }

运行结果:

最后看一下类图:

2、装饰者模式在源码中的体现

2.1 IO相关的类

装饰器模式在源码中也应用得很是多,在 JDK 中体现最明显的类就是 IO 相关的类,如BufferedReader、InputStream、OutputStream,看一下经常使用的 InputStream 的类结构图:

2.2 Spring中的装饰者模式

在 Spring 中的 TransactionAwareCacheDecorator类咱们也能够来尝试理解一下,这个类主要是用来处理事务缓存的,来看一下代码:

public class TransactionAwareCacheDecorator implements Cache {
    private final Cache targetCache;
    public TransactionAwareCacheDecorator(Cache targetCache) {
    Assert.notNull(targetCache, "Target Cache must not be null");
    this.targetCache = targetCache;
    }
    public Cache getTargetCache() {
    return this.targetCache;
    }
    ...
}

TransactionAwareCacheDecorator 就是对 Cache 的一个包装。 再来看一个 SpringMVC 中的装饰者模式 HttpHeadResponseDecorator 类:

public class HttpHeadResponseDecorator extends ServerHttpResponseDecorator {
    public HttpHeadResponseDecorator(ServerHttpResponse delegate) {
        super(delegate);
    }

    public final Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
        return Flux.from(body).reduce(0, (current, buffer) -> {
            int next = current + buffer.readableByteCount();
            DataBufferUtils.release(buffer);
            return next;
        }).doOnNext((count) -> {
            this.getHeaders().setContentLength((long)count);
        }).then();
    }

    public final Mono<Void> writeAndFlushWith(Publisher<? extends Publisher<? extends DataBuffer>> body) {
        return this.setComplete();
    }
}

3、 装饰者模式的优缺点

优势:

  • 装饰者是继承的有力补充,比继承灵活,不改变原有对象的状况下动态地给一个对象扩展功能,即插即用;

  • 经过使用不一样装饰类以及这些装饰类的排列组合,能够实现不一样效果;

  • 装饰者彻底遵照开闭原则。

缺点:

  • 会出现更多的代码,更多的类,增长程序复杂性;

  • 动态装饰时,多层装饰时会更复杂。

相关文章
相关标签/搜索