前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >设计模式之装饰者模式(三)

设计模式之装饰者模式(三)

作者头像
程序员小跃
发布2019-12-25 14:51:19
4560
发布2019-12-25 14:51:19
举报
文章被收录于专栏:程序员小跃

欢迎大家的持续关注,今天是周末,小编还继续学习着呢,给同样学习的你点个赞吧。上一次,我们结合第一篇推导出来的类图,到第二篇根据类图进行实际代码的编写,对装饰者模式有了一个整体的概念以及实战。不知道对你帮助如何呢?小编已经有门道了,看完接下来的一部分,你会恍然大悟,原来实际编码中你一直在用装饰者模式。

真实世界的装饰者:Java I/O

看到标题,是不是就很想往下看,到底是I/O中的什么呢,让你早已经拥有了装饰者模式的实践?就如书上给的描述,你第一次(还有第二次和第三次)看到这些API发出“哇”的惊叹时,放心,你不是唯一收到惊吓的人。下面,我们马上给出一个典型的对象集合,用装饰这来将功能结合起来,以读取文件数据:

image

装饰 java.io 类

你发现了没,java.io和之前的咖啡店其实没有太大的差异。这里使用了各种“输入”流装饰者来符合你的用途。 你会发现“输出”流的设计方式也是一样的。你还会发现Reader/Writer流和输入流/输出流的类相当类似。不过,出学过Java文件流的同学肯定知道,Java I/O也引出类装饰者的一个“缺点”:利用装饰者模式,常常造成设计中有大量的小类,数量实在太多,可能会造成使用此API程序员的困扰。不知道你之前有没有搞晕过呢,小编初入Java I/O的世界的时候,很是晕头转向。

编写自己的Java I/O 装饰者

那么,已经懂得了装饰者的精髓,我们自己来编写一个输入的装饰者如何呢?来一个小想法:编写一个装饰者,把输入流内的所有大写字符转成小写。赶紧行动吧。

代码语言:javascript
复制
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;

public class LowerCaseInputStream extends FilterInputStream {

    protected LowerCaseInputStream(InputStream in) {
        super(in);
    }

    public int read() throws IOException {
        int c = in.read();
        return (c == -1 ? c : Character.toLowerCase((char)c));
    }

    public int read(byte[] b,int offset,int len) throws IOException {
        int result = in.read(b, offset, len);
        for (int i = offset; i < offset+result; i++) {
            b[i] = (byte)Character.toLowerCase((char)b[i]);
        }
        return result;
    }

}
测试你的新Java I/O 装饰者

基于上面的装饰者,我们来实现下功能,看是否是符合你的需求呢?

代码语言:javascript
复制
public class InputTest {

    public static void main(String[] args) throws IOException{
        int c;
        try {
            // 设置FileInoutStream,先用BufferedInputStream装饰它,再用我们崭新的LowerCaseInputStream过滤器装饰它
            InputStream inputStream = new LowerCaseInputStream(
                    new BufferedInputStream(
                            new FileInputStream("test.txt")));

            while ((c = inputStream.read()) >= 0) {
                System.out.print((char)c);
            }
            inputStream.close();
        } catch (IOException e) {

        }
    }
}

// 输入内容:
I know the Decorator Pattern and HOW it's used in the JAVA.IO package.
// 运行结果
i know the decorator pattern and how it's used in the java.io package.

恭喜你,已经喜提装饰者模式,在设计模式的世界里又更进一步了。这里,我们通过咖啡厅卖升级订单系统,来了解装饰者模式一步步产生的过程;再通过实际的Java API中的I/O进一步巩固他,并用自定义的I/O功能实现,来结束此次的装饰者模式之旅,开不开心呢?

设计箱内的工具

还是按照之前的套路,总结下工具箱内新增的工具吧

  • OO基础 本次没有变化 抽象、封装、继承、多态
  • OO原则 封装变化 多用组合,少用继承 针对接口编程,不针对实现编程 为交互对象之间的松耦合设计而努力 对扩展开放,对修改关闭(现在有了开放-关闭原则引导我们。我们会努力的设计系统,好让关闭的部分和新扩展的部分隔离)
  • OO模式 『策略模式』 『观察者模式』 『装饰者模式』动态地将责任附加到对象上。想要扩展功能,装饰者提供有别于继承的另一种选择
遗留问题解答

哦,对了,上次还留下了一个新增的功能,在咖啡厅里顾客可以选择小杯、中杯、大杯的需求,调料根据咖啡容量收费。例如:小中大杯的咖啡加上豆浆,分别加收0.10,、0.15、0.20。那怎么做呢,请往下看。这里仅列举Soy类,其他类的代码请移步到GitHub上查看。

代码语言:javascript
复制
public class Soy extends CondimentDecorator {

    Beverage beverage;

    public Soy(Beverage beverage) {
        this.beverage = beverage;
    }

    @Override
    public String getDescription() {
        return beverage.getDescription() + " , Soy";
    }

    @Override
    public double cost() {
        double cost = beverage.cost();
        if (beverage.getSize() == Size.TALL) {
            cost += 0.10;
        } else if (beverage.getSize() == Size.GRANDE) {
            cost += 0.15;
        } else if (beverage.getSize() == Size.VENTI) {
            cost += 0.20;
        }
        return cost;
    }

}

至此,我们又学完了一个设计模式,装饰者模式。除了之前的要点之外,小编在这里还得提醒下大家,装饰者一般对组件的客户是透明的,除非客户程序依赖于组件的具体类型。你可以用无数个装饰者包装一个组件,但是这样会导致设计中出现许多小对象,如果过度使用,会让程序变得很复杂。所以,我们需要按需使用,而不是滥用噢。

已经陆陆续续学完了3个设计模式,不知道大家对这样的方式有没有不解,或者有没有更多的建议,小编都会虚心接受。下次课程,我们学习工厂模式。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-04-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 奔跑吧攻城狮 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 真实世界的装饰者:Java I/O
  • 装饰 java.io 类
  • 编写自己的Java I/O 装饰者
  • 测试你的新Java I/O 装饰者
  • 设计箱内的工具
  • 遗留问题解答
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档