天天看点

趣谈装饰器模式,让你一辈子不会忘

本文节选自《设计模式就该这样学》

来看这样一个场景,上班族大多有睡懒觉的习惯,每天早上上班都时间很紧张,于是很多人为了多睡一会儿,就用更方便的方式解决早餐问题,有些人早餐可能会吃煎饼。煎饼中可以加鸡蛋,也可以加香肠,但是不管怎么加码,都还是一个煎饼。再比如,给蛋糕加上一些水果,给房子装修,都是装饰器模式。

下面用代码来模拟给煎饼加码的业务场景,先来看不用装饰器模式的情况。首先创建一个煎饼battercake类。

然后创建一个加鸡蛋的煎饼battercakewithegg类。

再创建一个既加鸡蛋又加香肠的battercakewitheggandsausage类。

最后编写客户端测试代码。

运行结果如下图所示。

趣谈装饰器模式,让你一辈子不会忘

运行结果没有问题。但是,如果用户需要一个加2个鸡蛋和1根香肠的煎饼,则用现在的类结构是创建不出来的,也无法自动计算出价格,除非再创建一个类做定制。如果需求再变,那么一直加定制显然是不科学的。

下面用装饰器模式来解决上面的问题。首先创建一个煎饼的抽象battercake类。

创建一个基本的煎饼(或者叫基础套餐)basebattercake。

然后创建一个扩展套餐的抽象装饰器battercakedecotator类。

接着创建鸡蛋装饰器eggdecorator类。

创建香肠装饰器sausagedecorator类。

再编写客户端测试代码。

趣谈装饰器模式,让你一辈子不会忘

最后来看类图,如下图所示。

趣谈装饰器模式,让你一辈子不会忘

为了加深印象,我们再来看一个应用场景。需求大致是这样的,系统采用的是sls服务监控项目日志,以json格式解析,因此需要将项目中的日志封装成json格式再打印。现有的日志体系采用log4j + slf4j框架搭建而成。客户端调用如下。

这样打印出来的是毫无规则的一行行字符串。当考虑将其转换成json格式时,笔者采用装饰器模式。目前有的是统一接口logger和其具体实现类,笔者要加的就是一个装饰类和真正封装成json格式的装饰产品类。创建装饰器类decoratorlogger。

创建具体组件jsonlogger类。

可以看到,在jsonlogger中,对于logger的各种接口,我们都用jsonobject对象进行一层封装。在打印的时候,最终还是调用原生接口logger.error(string),只是这个string参数已经被装饰过了。如果有额外的需求,则可以再写一个函数去实现。比如error(exception e),只传入一个异常对象,这样在调用时就非常方便。

另外,为了在新老交替的过程中尽量不改变太多代码和使用方式,笔者又在jsonlogger中加入了一个内部的工厂类jsonloggerfactory(这个类转移到decoratorlogger中可能更好一些)。它包含一个静态方法,用于提供对应的jsonlogger实例。最终在新的日志体系中,使用方式如下。

对于客户端而言,唯一与原先不同的地方就是将loggerfactory改为jsonloggerfactory即可,这样的实现,也会更快更方便地被其他开发者接受和习惯。最后看如下图所示的类图。

趣谈装饰器模式,让你一辈子不会忘

装饰器模式最本质的特征是将原有类的附加功能抽离出来,简化原有类的逻辑。通过这样两个案例,我们可以总结出来,其实抽象的装饰器是可有可无的,具体可以根据业务模型来选择。

【推荐】tom弹架构:收藏本文,相当于收藏一本“设计模式”的书 本文为“tom弹架构”原创,转载请注明出处。技术在于分享,我分享我快乐! 如果本文对您有帮助,欢迎关注和点赞;如果您有任何建议也可留言评论或私信,您的支持是我坚持创作的动力。关注微信公众号『 tom弹架构 』可获取更多技术干货!