Decorator Pattern 装饰器模式

继承是拓展类功能最常见的手段,但是其缺点也很明显,其耦合程度较高。这里我们介绍一种新的方法来拓展类的功能——Decorator Pattern装饰器模式,其是结构性模式的一种,通过包装的方式实现动态增强、拓展已有对象的功能

设计模式
在这里插入图片描述

简介

在 Decorator Pattern 装饰器模式下,如果我们期望拓展已有对象的功能,那么就可以通过装饰者对象来包装该这个已有对象来实现。显然这种动态的方式比继承会更加灵活。具体地,装饰者对象内部会持有被装饰对象的引用,这样装饰者对象一方面用于实现拓展的功能,另一方面其会再将请求转发给被装饰的对象。在Java的IO流中就大量使用了该模式

这里我们以奔驰车Car为例来进行引入,对于一个BenzCar对象来说,其具备的基本功能就是乞丐版的Car。但实际上不同喜好的客户可能需要添加不同的配置。比如有人要加配座椅,有人要加配影音,还有人要加运动套件。试想一下,如果用继承的方式来实现不同配料组合下的各种Car。可以想见,整个子类将会非常庞大臃肿。那么这个时候,我们就可以通过装饰器模式来优雅的解决这个问题。在装饰器模式下,其通常有以下几个角色

  • 「抽象组件接口」 :被装饰对象 与 装饰者对象 需要实现同一个接口,以便装饰者对象拓展、增强被装饰对象的功能、行为。本文的例子下,就是一个Car接口,其定义了生成create()的方法,用于烹饪出一个Car
  • 「被装饰的具体对象」:一个实现上述接口的具体类,其通常是按基础、通用的原则来实现接口中定义的方法。在这里即为BenzCar类,其create只制造了一个乞丐版的Car
  • 「抽象装饰者」:在抽象装饰者中,其内部会持有被装饰对象引用来转发请求,在Java中一般通过抽象类来定义该角色。在本文实例中即为CarDecorator类
  • 「具体装饰者」:其是抽象装饰者的实现类,用于实现拓展的功能。在本文例子中,即为LeatherChairCarDecorator、VideoCarDecorator、SportCarDecorator类。用于给乞丐版的Car添加各种配置

实现

现在我们利用Java来实现本文所说的例子,首先我们定义一个被装饰者、装饰者共有的接口

/**
 * 抽象组件接口:Car
 */
public interface Car {
    /**
     * 创建Car
     */
    void create();
}

然后来实现一个被装饰的具体对象BenzCar类,可以看到其只是创建一个啥配置都没有的BenzCar

/**
 * 具体组件, 被装饰对象: BenzCar
 */
public class BenzCar implements Car {
    /**
     * 创建Car
     */
    @Override
    public void create() {
        System.out.println("奔驰车!");
    }
}

现在我们需要来给Car加各种配置了,首先定义一个抽象装饰者。可以看到其有一个car字段用于持有被装饰包装的对象

/**
 * 抽象装饰者
 */
public abstract class CarDecorator implements Car {
    protected Car car;

    public CarDecorator(Car car) {
        this.car = car;
    }

    @Override
    public void create() {
        if (car != null) {
            car.create();
        }
    }
}

然后通过具体的装饰者来实现给Car添加不同的配置,这里我们提供了三个装饰者,分别用于给Car添加真皮座椅,影音系统、运动套件

/**
 * 具体装饰者:给car加真皮座椅
 */
public class LeatherChairCarDecorator extends CarDecorator {
    public LeatherChairCarDecorator(Car car) {
        super(car);
    }

    @Override
    public void create() {
        System.out.print("加真皮座椅,");
        super.create();
    }
}
/**
 * 具体装饰者:给car加运动套件
 */
public class SportCarDecorator extends CarDecorator {
    public SportCarDecorator(Car car) {
        super(car);
    }

    @Override
    public void create() {
        System.out.print("加运动套件,");
        super.create();
    }
}
/**
 * 具体装饰者:给car加影音系统
 */
public class VideoCarDecorator extends CarDecorator {
    public VideoCarDecorator(Car car) {
        super(car);
    }

    @Override
    public void create() {
        System.out.print("加影音系统,");
        super.create();
    }
}

现在,我们来实际测试下,看看通过装饰器模式能不能拿到顶配的奔驰车。可以看到由于被装饰对象、装饰者都实现了同一个接口,所以可以包装多层整一个至尊版车

/**
 * 测试用例
 */
public class DecoratorPatternDemo {
    public static void main(String[] args) {
        Car car = new BenzCar();
        car.create();

        // 给乞丐版Car加个真皮座椅
        Car leatherChairCa = new LeatherChairCarDecorator(car);
        leatherChairCa.create();

        // 给真皮座椅Car再加个运动套件
        Car sportPizza = new SportCarDecorator(leatherChairCa);
        sportPizza.create();

        // 给真皮座椅、运动Car再加个莹莹系统
        Car superCar = new VideoCarDecorator(sportPizza);
        superCar.create();
    }
}
测试结果
在这里插入图片描述

应用

装饰器模式在io中具有实际的应用,FilterInputStream实际上没有做任何事情,只是持有了InputStream对象,所以呢,比如我们常用的FileInputStream,它并没有缓冲功能,我们每次调用read,都会向操作系统发起调用索要数据。假如我们通过BufferedInputStream来装饰它,那么每次调用read,会预先向操作系统多拿一些数据,这样就不知不觉中提高了程序的性能。

输入流
在这里插入图片描述
输出流
在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值