一、什么是柔性设计
这个概念来自《领域驱动设计——软件核心复杂性应对之道》一书:
为了使项目能够随着开发工作的进行加速前进,而不会由于它自己的老化停滞不前,设计必须要让人们乐于使用,而且易于修改。 《领域驱动设计——软件核心复杂性应对之道》
说简单点,指的是系统保持良好的扩展性,当有新需求时,旧的系统需要能容易、方便、高效的修改,以达到快速交付。
二、如何进行柔性设计
书中讲了几个模式:
1、INTENTION-REVEALING INTERFACES(意图提示接口)
网上有不同的中文翻译,这里翻译的可能不太准确,所以把原文说出来了。
这个模式的意思是类和方法(包括接口)从名字上要能描述它们的效果和目的,而不是表示它们是通过何种方式达到目的的,即命名描述类(方法)的作用,而不应该描述实现。
如果开发的同学为了使用一个类或一个方法必须研究它的实现,那封装就失去了价值,进而设计的概念基础已经被误用了,所以可能被误用。
2、SIDE-EFFECT-FREE FUNCTION(无副作用函数)
1)、修改会产生副作用(改变状态);
2)、返回结果而不产生副作用的操作叫做函数;
3)、将修改和函数分开。确保导致状态改变的方法不返回领域数据,并尽可能保持简单。
4)、实在有复杂的逻辑,主要针对可能产生副使用的,尽量放到Value Object中(DDD相关概念,这里不详述)。
3、ASSERTION(断言)
1)、在不了解内部实现需要知道操作的结果,即一个方法知道执行后的结果或状态是什么样的是确定的;
2)、把操作的后置条件及AGGREGATE(DDD相关概念,这里先不描述)的固定规则描述清楚;
3)、寻找概念上内聚的模型,以便方便开发人员推断预期的ASSETION。
还有其它的CONCEPTUAL CONTOUR(概念轮廓)、STANDALONE CLASS(独立的类)、CLOSURE OF OPERATION(闭合操作),这里不一一进行说明,有兴趣可以翻译原文。
下面看实际的例子,作者举例了一个调漆的应用程序,刚开始类图如下:
其中paint方法根本猜不出它的使用,想知道它干了什么必须阅读源代码。
public void paing(Paint paint){
v = v + paint.getV();
//计算混合后的颜色
//计算新的r, b, y的值
}
从代码上看,这个方法是把两种油漆(Paint对象表示)混合到一起,结果是油漆的体积增加了,并将颜色变为混合颜色。
逐步重构步骤如下:
1、将模型中重要的颜色概念表达出来
Paint类有r, y, b代表颜色,颜色在这里是一个重要的概念,但没被表达出来,以INTENTION-REVEALING INTERFACES模式作参考,我们需要将这个概念表达出来,因此需要单独用一个类描述:
2、混合方法参数调整
调漆时,Paint对象本身被改变了,它是一个具有生命周期的实体。
Pigment Color(颜色)则还是表示那种颜色,因此后者是不可变的,是Value Object,调漆的结果是产生一个新的颜色,以SIDE-EFFECT-FREE FUNCTION模式作参考,我们需要将修改放到Value Object中。
可以看到mixedWith的方法的参数接受一个颜色对象,输出也是一个颜色对象。混合后我们不用跟踪Paint对象的状态,因为结果是一个新的颜色对象了。
3、新的类层次
当一种颜色混合另一种颜色之后,通过上面的ASSERTION,规则如下:
被混合颜色的volume增加,但混合者的volume不变。
这里的规则不容易让人理解,现实的情况是A混合B之后,B的volume全部转到A了。
因此可以用另一个易于理解的规则:
混合之后油漆的总体积不变。
还有另一个需求,程序最后需要报告混合之前的油漆清单,因此程序中需要记录混合者的信息,又需要记录混合者的信息,又要满足上面的规则,从对模型的直观理解有一个好的方案,把一个对象加入到一个集合中,这种集合代表一种新的调漆程序,以下是最终的模型。