小灰 程序员小灰




—————  第二天  —————


————————————














装饰器模式都包含哪些核心角色呢?


1. Component接口


在我们上面的例子中,Component接口相当于汽车接口,所有的被包装类、包装类,都继承于这个接口。


2. ConcreteComponent类


ConcreteComponent类是被包装的实现类。在例子中,奔驰汽车、宝马汽车、特斯拉汽车都属于这个角色。


3. Decorator抽象类


所有的包装类,都继承自Decorator抽象类,而Decorator类又实现了Component接口,这么做是为了实现多层嵌套包装。


4ConcreteDecorator类


具体的包装类,用于扩充被包装类的功能,比如例子中的自动驾驶功能、飞行功能扩展。



这四大核心角色的关系是怎样的呢?我们可以用装饰器模式的UML类图来表达:




首先是汽车接口,也就是Component这个角色,里面定义了run这个行为:


public interface Car {
    void run();
}


接下来是各种汽车的实现类,也就是ConcreteComponent角色,不同的汽车对于run行为有着不同的实现:


public class BenzCar implements Car{
    @Override
    public void run() {
        System.out.println("奔驰开车了!");
    }
}

public class BmwCar implements Car{
    @Override
    public void run() {
        System.out.println("宝马开车了!");
    }
}

public class TeslaCar implements Car{
    @Override
    public void run() {
        System.out.println("特斯拉开车了!");
    }
}


下面是装饰器的抽象类,也就是Decorator角色,这个角色包含了被装饰的成员对象:


public class CarDecorator implements Car {

    protected Car decoratedCar;

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

    public void run(){
        decoratedCar.run();
    }
}


或许有人会觉得奇怪,为什么装饰器类也要实现Car接口呢?这正是装饰器模式的灵活之处。


继承自Car接口,可以让每一个装饰器本身也可以被更外层的装饰器所包装,包装的方式就是把Car对象作为参数,传入到外层装饰器的构造函数当中。


接下来是具体的装饰器实现类,也就是ConcreteDecorator角色。这些装饰器同样实现了run的行为,一方面会调用被包装对象的run方法,一方面会进行某些扩展操作(比如自动驾驶、飞行):


public class AutoCarDecorator extends CarDecorator {

    public AutoCarDecorator(Car decoratedCar){
        super(decoratedCar);
    }

    @Override
    public void run(){
        decoratedCar.run();
        autoRun();
    }

    private void autoRun(){
        System.out.println("开启自动驾驶");
    }
}

public class FlyCarDecorator extends CarDecorator {

    public FlyCarDecorator(Car decoratedCar){
        super(decoratedCar);
    }

    @Override
    public void run(){
        decoratedCar.run();
        fly();
    }

    private void fly(){
        System.out.println("开启飞行汽车模式");
    }

}


最后,是我们的客户端类。客户端类负责创建被包装对象和装饰者,并决定如何进行包装和执行:


public class Client {

    public static void main(String[] args) {
        Car benzCar = new BenzCar();
        Car bmwCar = new BmwCar();
        Car teslaCar = new TeslaCar();
        //创建自动驾驶的奔驰汽车
        CarDecorator autoBenzCar = new AutoCarDecorator(benzCar);
        //创建飞行的、自动驾驶的宝马汽车
        CarDecorator flyAutoBmwCar = new FlyCarDecorator(new AutoCarDecorator(bmwCar));

        benzCar.run();
        bmwCar.run();
        teslaCar.run();
        autoBenzCar.run();
        flyAutoBmwCar.run();
    }
}



以输入流为例,为了满足不同输入场景,JDK设计了多种多样的输入流,包括ByteArrayInputStream、FileInputStream等等。


这些输入流都继承自共同的抽象类:InputStream。


与此同时,为了给这些输入流带来功能上的扩展,JDK设计了一个装饰器类,FilterInputStream。该继承自InputStream并且“组合”了InputStream成员对象


从FilterInputStream类派生出了许多装饰器子类,包括BufferedInputStream,DataInputStream等等,分别提供了输入流冲,以及从输入流读取Java基本数据类型等额外功能。


©著作权归作者所有:来自51CTO博客作者mob604756fef1ec的原创作品,如需转载,请注明出处,否则将追究法律责任

更多相关文章

  1. 快递查询、快递单识别、电子面单、家寄件等接口代码-快递100JAVA
  2. 【PHP 面向对象】面向对象(OOP)编程知识点归纳总结(二)
  3. PHP:oop->抽象类/接口/后期静态绑定/单例模式连接数据库 Db类中
  4. php之单例模式连接数据库
  5. SpringBoot 项目配置 Swagger 接口api 搭建 REST
  6. 从零搭建Spring Boot脚手架(4):手写Mybatis通用Mapper
  7. 给你一个理由学习Linux,树莓派4免费送
  8. 以接口为主导的设计中, 我在使用的框架模式
  9. UI 自动化测试在有赞的实践

随机推荐

  1. sqlloader导出数据和导入数据
  2. ADO-excel,SQL查询中的问题
  3. 使用 docker-compose 安装 MySQL 5.5 记
  4. POI往Mysql中,导入导出Excel
  5. mysql的几种SQL语句
  6. sql2005 数据库连接的时候,无法连接外部服
  7. 无法弄清楚mySQL语法错误的来源
  8. 如何在大表中选择重复的行/记录?
  9. JSP连接Mysql的数据库连接池配置相关
  10. MySQL各存储引擎的区别及其启动方法