1. 引言
学习模式的时候,会不会这种想法,不就是接口,抽象类,属性组合这些基本语法吗?为啥搞这么复杂?
模式并不会改变编程语言的基础,我们是不是可以换个角度,从编程语言提供的基础能力来审视下。(本文使用JAVA语法展示,其他语言可能略有不同)
VS对比
- 设计模式是通过场景,然后解释场景的解决方案。
- 我们要做的是倒过来,先看语言有几种解决方案,合适的场景再选用方案的排列组合。
2. 类的组合
2.1 通过属性组合
面向对象的语言(比如JAVA)的类可以有属性与方法;属性可以是接口,也可以是类,属性提供是组合能力,来看下属性的威力,通过属性我们可以把职责委托出去。
来看下图,处于中央位置的服务类,把不同的功能点委托给ABCDE来处理,自身协调调度ABCDE就可以:
这样做的几点思考:
- 变换点得到了分离,一个变化点发生变化,只需要改少数类的代码:比如服务A包装了业务A的变化,如果业务A发生变化,那么只需要修改服务类A就可以。
- 服务类并不太关心ABCDE是类还是接口,委托出去了就可以。
- 委托选用类,还是接口没有那么重要(很多人认为很重要),代码是可以改的,如果需要不同实现,必然会改成接口;相反如果永远只有一种实现,干嘛一定要出现一个接口?!
2.2 类持有接口
QA:为什么要讨论类持有接口,而不是类持有类呢?
因为模式都是处理复杂问题的,所以模式的设计基本都是持有接口(可以各种变换),持有类的场景上图就够说明了。持有类依然是一个强大的武器,简单并不意味弱小
来看下下图,具体类通过接口分离出一个变化点,接口有不同的实现。
- 策略模式就是把策略(变化点)委托出去,可以有不同的策略实现。
- Build模式就是把对象创建过程(变换点)委托出去。
2. 类的继承
继承提供了一种复用机制,同时也提供了封装变化的机制,变化封装不如组合彻底。
这种不彻底封装有个好处,最少只要两个类,就可以完成复用和扩展(如果采用组合,至少要2个类+一个接口)。
比如模板方法模式,就利用了这种简化的特质:具体类里写框架代码,调用了抽象的方法,每个子类实现抽象方法。
补充知识1:JAVA提供的匿名类和Lamda表达式,可以让模板方法这种继承写起来更简单。
补充知识2:JAVA的接口已经开始支持Default方法实现,抽象父类也可以是接口,在某些场景,接口和抽象类是可以替换的。
模板方法可参考:模板方法设计模式与生活的关系
3.同时使用继承+组合
其实就是桥梁模式了,通过继承和组合分别暴露一个变化点,可以同时支持两个维度的独立变化。