博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
装饰模式(Decorator)
阅读量:6146 次
发布时间:2019-06-21

本文共 2281 字,大约阅读时间需要 7 分钟。

思想概要

装饰模式是对里氏替换的一种扩充,里式替换原则,即:基类可以出现的地方都可以替换为子类。这似乎就是”继承“的标准定义嘛,但是我们的前辈常常告诫我们,继承是危险的,要谨慎使用继承,除非你能够证明A is B,而不是A like B。对于所有A like B的地方,都要积极的使用组合,而不是继承。继承之所以不受待见,是因为它破坏了封闭原则。子类不仅继承了基类的public函数,同时它也可以访问基类的protected函数,而这些函数本质上是包封闭的,开发者们不会对封闭函数的一致性负责,一旦基类在今后的某次升级中被改变,那子类就很有可能不能正常运行。既然不推荐使用继承,那对已有类的功能加强就落在了以组合为基本架构的装饰模式上。组合的好处是你无法访问public以外的函数,可以充分享受public函数拥有的一致性福利,不用担心随着版本的不同而功能失效。

依旧是盗图,请原谅。上图展示了装饰者模式的UML结构,真实类为ConcreteComponent,基础装饰者为Decorator,类似于代理模式,装饰者也是要调用真实类的API来实现功能。但是就像我们之前所说的一样,装饰者不是真实类的子类,它不通过继承来扩展功能,而是组合了真实类,同时,为了实现外部接口的一致性,它实现了Componet接口,外部代码可以像使用真实类一样使用装饰者

不同于代理模式,代理模式的使用者们不太在意代理类做了哪些事,因为代理者本身不扩展核心功能,而使用装饰者模式的用户更多的是强调装饰者们扩展了哪些功能,他们更在意装饰者的存在。所以在类图里你可以看到,除了基本装饰者(Decorator)外,还有继承自基础装饰者的ConcreteDecoratorA和ConcreteDecoratorB,因为它们各自扩展不同的功能,所以会分化出各种类,而在代理模式中,你几乎不会看到代理者还有子类。

讲到装饰者模式的具体事例,永远逃不掉加糖加奶咖啡的例子,很无聊但是很有代表性,你值得看看。

咖啡可以加糖也可以不加糖,可以加奶也可以不加奶,当然也可以既加糖又加奶。这个问题的着眼点其实已经不是咖啡了,它不再重要,重要的是糖和奶这两个装饰属性。这就是上面提到的,使用装饰者的客户往往不在乎真实类的功能,他们更在乎装饰者扩展了哪些内容。我们通过具体代码来看看它们是如何工作的:

public interface ICafe {    /* API */    void getCafe();}

这是咖啡接口,只有”要咖啡“这个基本API。

public class ConcreteCafe implements ICafe {    @Override    public void getCafe() {        System.out.println("Make cafe");    }}

这是原味咖啡制作类,仅仅做一杯黑咖啡

public class ConcreteDecorator implements ICafe {    private final ICafe cafe;        public ConcreteDecorator(ICafe ref) {        cafe = ref;    }    @Override    public void getCafe() {        cafe.getCafe();    }}

装饰者基类,没有追加任何功能,仅仅调用接口类的共有函数。

public class SugarDecorator extends ConcreteDecorator {    public SugarDecorator(ICafe ref) {        super(ref);    }    @Override    public void getCafe() {        super.getCafe();        System.out.println("Add sugar");    }}

加糖咖啡类,仅仅是在做咖啡之后加了一块糖

public class MilkDecorator extends ConcreteDecorator {    public MilkDecorator(ICafe ref) {        super(ref);    }    @Override    public void getCafe() {        super.getCafe();        System.out.println("Add milk");    }}

加奶咖啡,仅仅是在做咖啡后加了点奶

public class Launcher {    public static void main(String[] args) {            ICafe cafe = new MilkDecorator(new SugarDecorator(new ConcreteCafe()));        cafe.getCafe();    }}

检验结果的客户代码。它要了杯加糖又加奶的咖啡,运行结果是:

Make cafeAdd sugarAdd milk

总体来说,装饰类比较好掌握,不断的对基础类的装饰可以得到复杂的功能,这比修改实际代码更快或更好。

转载于:https://www.cnblogs.com/mubawa/p/9618978.html

你可能感兴趣的文章
SpringMVC权限管理
查看>>
spring 整合 redis 配置
查看>>
redhat6.1下chrome的安装
查看>>
cacti分组发飞信模块开发
查看>>
浅析LUA中游戏脚本语言之魔兽世界
查看>>
飞翔的秘密
查看>>
Red Hat 安装源包出错 Package xxx.rpm is not signed
查看>>
编译安装mysql-5.6.16.tar.gz
查看>>
类与成员变量,成员方法的测试
查看>>
活在当下
查看>>
每天进步一点----- MediaPlayer
查看>>
PowerDesigner中CDM和PDM如何定义外键关系
查看>>
跨域-学习笔记
查看>>
the assignment of reading paper
查看>>
android apk 逆向中常用工具一览
查看>>
MyEclipse 报错 Errors running builder 'JavaScript Validator' on project......
查看>>
Skip List——跳表,一个高效的索引技术
查看>>
Yii2单元测试初探
查看>>
五、字典
查看>>
前端js之JavaScript
查看>>