整理 Java I/O (九):装饰模式(Decorator)和过滤流 - FilterInput/OutputStream、FilterReader/Writer

装饰模式

有时候我们需要拓展一个类的功能或者给类添加附加职责,一种方式是创建继承自该类的新类,另外一种方法是创建新类,然后将该类的对象作为参数传入,后面这种方法就是装饰模式。装饰模式就是创建一个包装对象,来装饰包裹的真实的对象。

  • 装饰对象和真实对象有相同的接口。这样客户端对象就能以和真相对象相同的方式和装饰对象交互。

  • 装饰对象包含一个真实对象的引用。

  • 装饰对象接收所有来自客户端的请求,它把这些请求转发给真实的对象。

  • 装饰对象可以在转发这些请求以前或者以后增加一些新功能。

装饰模式比继承更加灵活机动,同时也意味着更多的复杂性,装饰模式会导致设计中出现许多小类,过度使用会使得程序变得复杂。

我们打个比方来解释一下这个装饰模式:

面粉公司要进军手机业,然后公司想要出多款机型去占领不同的市场:

  • 针对年轻人的高音质手机

  • 针对商务人士的长待机手机

  • 年度旗舰机,又高音质,又长待机

有一种解决方案是去富士康租三条生产线嘛,每条生产线生产一种手机,当然,这种方法也可以,但是如果又出来多种机型呢?总不能每个机型都去租一条生产线吧,多费钱!另外一种解决方法是只租一条生产线,生产基础功能的手机,然后在需要生产音乐手机的时候把高音喇叭装上去,需要生产待机手机时候,就把大容量电池装上去...

基础手机模型

public interface Phone {
    public void call();//手机基础功能---打电话
}

基础手机实例

public class BasicPhone implements Phone {

    @Override
    public void basicAbility() {
        System.out.println("通话...");
    }
}

这里就需要针对各种机型来做出相应的包装了,提供一个“包装模板”

public abstract class PhoneDecorate implements Phone {
    private Phone phone;

    public PhoneDecorate(Phone phone){
        this.phone = phone;
    }

    @Override
    public void basicAbility() {
        this.phone.basicAbility();
    }
}

针对音乐手机做包装

public class MusicPhoneDecorate extends PhoneDecorate{

    public MusicPhoneDecorate(Phone phone) {
        super(phone);
    }

    @Override
    public void basicAbility() {
        // TODO Auto-generated method stub
        super.basicAbility();
        playMusic();
    }

    private void playMusic(){
        System.out.println("播放音乐..");
    }
}

针对商务手机做包装

public class BigBatteryPhoneDecorate extends PhoneDecorate {

    public BigBatteryPhoneDecorate(Phone phone) {
        super(phone);
    }

    @Override
    public void basicAbility() {
        super.basicAbility();
        BigBattery();
    }

    private void BigBattery() {
        System.out.println("超大电池容量");
    }
}

现在就可以上生产线了

public class PhoneDemo {
    public static void main(String[] args) {

        //生产基础手机
        Phone basicPhone = new BasicPhone();
        basicPhone.basicAbility();

        System.out.println("======================");

        //生产音乐手机
        PhoneDecorate musucPhone = new MusicPhoneDecorate(basicPhone);
        musucPhone.basicAbility();

        System.out.println("======================");

        //生产商务手机
        PhoneDecorate batteryPhone = new BigBatteryPhoneDecorate(basicPhone);
        batteryPhone.basicAbility();

        System.out.println("======================");

        //生产旗舰手机
        PhoneDecorate proPhone = new BigBatteryPhoneDecorate(new MusicPhoneDecorate(basicPhone));
        proPhone.basicAbility();

    }
}

输出结果:

通话...
======================
通话...
播放音乐..
======================
通话...
超大电池容量
======================
通话...
播放音乐..
超大电池容量

解释一下装饰模式

        //生产音乐手机
        PhoneDecorate musucPhone = new MusicPhoneDecorate(basicPhone);
        musucPhone.basicAbility();

首先MusicPhoneDecorate对象的参数是一个BasicPhone对象,而这个对象实现了Phone接口。
紧接着MusicPhoneDecorate对象调用了其basicAbility()方法,实际上是调用了其父类的basicAbility()方法,因为

super.basicAbility();

去看其父类

public abstract class PhoneDecorate implements Phone {
    private Phone phone;

    public PhoneDecorate(Phone phone){
        this.phone = phone;
    }

    @Override
    public void basicAbility() {
        this.phone.basicAbility();
    }
}

其父类调用的正式传入的参数的BasicPhone对象的basicAbility方法,也就是说,手机的"通话..."功能是BasicPhone对象提供的。
紧接着MusicPhoneDecorate对象在basicAbility方法内部又调用了playMusic方法,也就是说这个播放音乐的功能是另外添加的,就相当于一个“装饰物”。
是不是清楚一些了??

过滤流

之前的装饰模式中说过,装饰模式中有一个抽象装饰类,来帮助我们衍生各种不同功能的具体装饰类,Java IO 体系中也有这样的抽象装饰类:

  • FilterInputStream

  • FilterOutputStream

  • FilterReader

  • FilterWriter

去看一下他们的源码就会发现,他们只是传入一个抽象类,由他们的子类(具体装饰类)去添加一些具体的功能。

FilterInputStream常用的子类有:

  • BufferedInputStream

  • DataInputStream

FilterOutputStream常用的子类有:

  • BufferedOutputStream

  • DataOutputStream

FilterReader常用的子类有:

  • 就一个PushbackReader 子类,但不常用,哈哈

FilterWriter常用的子类有:

  • 压根儿没有子类

参考资料

http://www.jianshu.com/p/eda2a396f572
http://www.jianshu.com/p/24d88fb3fe18

Copyright© 2020-2022 li-xyz 冀ICP备2022001112号-1