装饰者模式

装饰者模式

老样子,先说一个通俗易懂的例子,先把装饰者模式描述一下。

QQ秀大家应该都知道吧,反正我高中那会,谁要是有一套高颜值的QQ秀,那绝对是班里最亮丽的仔,我们就以QQ秀为例子说说这个装饰者模式,先附上一张QQ秀截图:

然后我们给QQ秀装饰 上衣、裤子、鞋子、礼物、背景,那我们的QQ可能就会变的很好看:

这么就是一个装饰模式了。

接下来,我们用代码的形式来模拟给QQ秀穿衣服加背景

装饰者模式的四个角色

  1. 抽象构件角色(QQShow)
  2. 具体构件角色(ConcreteQQShow)
  3. 装饰角色(Decorator)
  4. 具体装饰角色(ClothesDecorator、PantsDecorator、ShoesDecorator、BankgroundDecorator)

UML

代码演示

/**
 * 1、QQ秀 接口
 */
public interface QQShow {
    void operator();
}
/**
 * 2、具体 QQ秀 实现类
 */
public class ConcreteQQShow implements QQShow {
    @Override
    public void operator() {
        System.out.print("装饰QQ秀,");
    }
}
/**
 * 3、装饰类
 */
public class Decorator implements QQShow {

    // 持有被装饰者对象
    private QQShow qqShow;

    // 构造器方式,初始化被装饰者
    public Decorator(QQShow qqShow) {
        this.qqShow = qqShow;
    }

    @Override
    public void operator() {
        qqShow.operator();
    }
}
/**
 * 4、给QQ秀添加衣服
 */
public class ClothesDecorator extends Decorator {
    /**
     *
     * 在这里卡主了一会,平时都是默认无参构造方法,没太在意这种问题
     * 还是要科普一下基础知识:
     * 子类继承父类,若父类存在[有参构造方法],子类也必须存在(编译器会提示,根据提示直接创建即可)
     * 实例化子类,构造方法执行顺序:
     * 例如:A extends B extends C; C c = new C(); 构造方法执行顺序为 A > B > C
     */
    public ClothesDecorator(QQShow qqShow) {
        super(qqShow);
    }

    @Override
    public void operator() {
        super.operator();
        System.out.print("穿上衣服,");
    }
}
/**
 * 5、给QQ秀添加裤子
 */
public class PantsDecorator extends Decorator {

    // 父类有默认构造器,子类必须也存在默认构造器
    public PantsDecorator(QQShow qqShow) {
        super(qqShow);
    }

    @Override
    public void operator() {
        super.operator();
        System.out.print("穿上裤子,");
    }
}
/**
 * 6、给QQ秀添加鞋子
 */
public class ShoesDecorator extends Decorator {

    public ShoesDecorator(QQShow qqShow) {
        super(qqShow);
    }

    @Override
    public void operator() {
        super.operator();
        System.out.print("穿上鞋子,");
    }
}
/**
 * 7、给QQ秀添加背景
 */
public class BackgroundDecorator extends Decorator {

    public BackgroundDecorator(QQShow qqShow) {
        super(qqShow);
    }

    @Override
    public void operator() {
        super.operator();
        System.out.print("加上背景,");
    }
}
public static void main(String[] args) {
        // 实例化 QQ秀
        QQShow qqShow = new ConcreteQQShow();

        // 给QQ秀穿上衣服
        Decorator clothes = new ClothesDecorator(qqShow);

        // 给QQ秀穿上裤子
        Decorator pants = new PantsDecorator(clothes);

        // 给QQ秀穿上鞋子
        Decorator shoes = new ShoesDecorator(pants);

        // 给QQ秀添加背景
        Decorator backGround = new BackgroundDecorator(shoes);

        backGround.operator();
}

给大家一点建议,如果看设计模式有点懵的话,直接上手按照网上大神的方式先抄下来,然后再慢慢领悟其中的奥义。

装饰模式总结:

装饰模式从代码结构上来看,其用意就是不改变目标类的情况下,给目标类动态添加功能,让其功能增强,比如说:有个需求,车站买票的功能,后期有需求说,军人、残疾人买票可通过VIP通道不用排队,那么就可以在不改变原先的买票功能(目标类)上装饰一个VIP通道功能。

Java的I/O流中,就是装饰者模式,如果读者对I/O流体系比较混乱的话,不妨利用装饰者模式去理理思路。

OutputStream和InputStream就对应于抽象构件角色(QQShow),

FileInputStream和FileOutputStream就对应具体构件角色(ConcreteQQShow),

FilterOutputStream和FilterInputStream就对应着装饰角色(Decorator),

而BufferedOutputStream,DataOutputStream等等就对应着具体装饰角色。

所以我们也可以自定义一个具体的装饰角色去装饰FileInputStream或FileOutputStream

首先我们来看一个简单的例子,使用 java io 输出数据到文件中:

   /**
     * java io 在文件里面写入数据
     */
    public static void javaIo() throws Exception {
        // 目标类实现类
        FileOutputStream fos = new FileOutputStream("D:\\decorator.txt");
        // 装饰类,持有目标类
        FilterOutputStream fios = new FilterOutputStream(fos);
        // 具体装饰类
        BufferedOutputStream bos = new BufferedOutputStream(fios);
        // 写入数据
        bos.write("abcdef".getBytes());
        bos.close();
    }

打开文件,看到写入的内容:

然后我们自定义一个具体的装饰类:

/**
 * 自定义,具体装饰类
 */
public class MyOutputStream extends FilterOutputStream {
    public MyOutputStream(OutputStream out) {
        super(out);
    }
    @Override
    public void write(byte b[]) throws IOException {
        super.write(b);
        // 写入完数据之后,我们再给写入的数据加上别的内容,起到装饰的效果
        super.write("装饰一下".getBytes());
    }
}

使用我们自定义的具体装饰类,来实现以下写入数据到文件中

   /**
     * 自定义装饰类,装饰写入的数据
     */
    public static void myIo() throws Exception {
        // 目标类实现类
        FileOutputStream fos = new FileOutputStream("D:\\decorator.txt");
        // 装饰类,持有目标类
        FilterOutputStream fios = new FilterOutputStream(fos);
        // 自定义 - 具体装饰类
        MyOutputStream bos = new MyOutputStream(fios);
        bos.write("abcdef".getBytes());
        bos.close();
    }

然后看一下文件里面的内容:

哈哈,看到了吧,我们虽然只写入了abcdef,但是我们用的是自己定义的具体装饰类,在abcdef后面增加了内容,起到了装饰的结果。

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值