2个观点,带你重新理解设计模式
文章首发于个人博客 shuyi.tech,欢迎点击原文跳转阅读。
设计模式说白了就是传统经验的总结,它能让我们在合适的场景使用合适的模式,从而加快我们的编程速度,也能提高系统的扩展性、稳定性。这里我想就设计模式提出两个观点:
1、设计模式是用来承载复杂的业务逻辑的。
2、用好设计模式需要从变化的角度去理解业务。
设计模式用于承载复杂的业务逻辑
如果你的业务非常简单,那么基本上是不需要用到设计模式的。只有当你的业务变得复杂的时候,这才需要用到设计模式。这也是为什么设计模式总是和重构一起被提到,因为重构的时候就说明这个系统相对比较复杂了,不然也不会做崩了。
那为什么说设计模式用于承载复杂业务呢?
我们都知道设计模式都有一个类图,这些类图其实用于表示这种模式对于变化的分离(关于变化在下文会说到)。设计模式使用类图来存储复杂的业务关系,使得开发者可以专注于业务逻辑的开发,所以说设计模式用于承载复杂的业务。
如上图所示是策略模式的类图,Context 类是上下文类,在该类中初始化了具体的策略。Strategy 则是策略接口,ConcreteStrategies 则是具体的策略类。这个类图使用 Strategy 与 ConcreteStrategies 的实现关系,将不同策略隔离开来,开发者不需要去关心策略彼此的关系。而使用 Context 与 Strategy 的关系隔离开来,开发者不需要去关心怎么选择策略。所以说 Strategy 与 ConcreteStrategies 的关系、Context 与 Strategy 的关系(类关系)承载了一些逻辑,而就是我所说的:设计模式承载了复杂的业务逻辑。
使用设计模式去承载复杂的业务逻辑,有好也有坏,但总体来说好处比较多。坏处就是对初学者非常不友好,可能他们完全看不懂代码。好处则是熟悉设计模式的人,用设计模式可以一目了然地知道业务关系,它们使用设计模式作为语言来表达业务的关系。其次,各块代码之间相互隔离,稳定性、扩展性非常好。
从变化的视角去理解业务
我工作了5、6年,本该学什么东西都很快。但我却依旧花了一两个月的时间,慢慢琢磨每个设计模式的本质。经过一段时间的琢磨,我发现了一个理解设计模式的全新视角:变化。
很多时候我们去理解一个设计模式,我们不能仅仅知道它的类图是怎样的,这样的学习完全流于表面。我们需要知道它为什么要这么做?它这样做的原因是什么?它在什么场景下使用?经过这样的一番思考,我发现:所有设计模式的诞生,都是为了隔离变化。
在应用的时候,我们需要去分析需求中哪些是变化的,哪些是固定的。然后使用设计模式去承载变化的东西,封装固定的东西。
工厂方法模式,本质上是为了隔离创建者与使用者。为什么?因为创建者可能是多变的,而使用者则是确定的。
抽象工厂模式,本质上是为了隔离产品族。为什么?因为产品族相对是多变的,所以要把变化的东西剥离出去。
桥梁模式,本质上是为了将实现剥离出去。为什么?因为实现是多变的,而抽象则是确定的,所以要剥离出去。
代理模式,本质上是为了将多变的控制玻璃出去。为什么?因为代理本身是为了增强对目标对象的控制,那其控制的标准可能就很多,今天可能要这个条件,明天可能要那个条件。因此需要将变化的东西剥离出去,因此有了代理类。有了代理类,我们不会污染目标类。
责任链模式,变化的是对于责任的处理。
命令模式,变化的可能是命令的具体做法、执行标准。
迭代器模式,不变的是迭代模式,变化的是不同的数据结构,迭代算法不一样。
中介者模式,变化?关联?更多是帮助梳理关系。
备忘录模式,变化?没有特别大,其实就是对于类的状态记录,单独由一个类来控制。
观察者模式,变化?对于观察后的处理是不同的,是变化的。相同的是,他们都要观察获取触发。
状态模式,变化的是这些状态。
策略模式,变化的是这些具体的做法。
模板方法,变化的是具体的某个细节实现,不变的是整个流程算法。
访问者模式,变化的是不同的访问对象,不变的是我自身的处理流程(例如文件树的遍历)。
那我们应该如何从「变化」的角度去分析业务呢?有什么可遵循的套路吗?有什么最佳实践吗?
首先,我们还是应该从业务的复杂度入手,看看业务是否足够复杂。设计模式的本质是用来承载复杂的业务结构,如果业务目前还不清晰,并且也很简单,那就不要用设计模式了。
其次,我们还是应该从变化这个角度入手,分析业务系统中哪些是变化的,哪些是不变的。这个就要求你对业务非常熟悉,只有熟悉业务才能弄清楚变化在哪里。
最后,分析这种变化的各个实体关系,看看是否符合访问者模式的特征(有固定的成分,又需要变化,又不是继承关系)。