存在许多领域建模的方法,但是在过去的十年左右,面向对象(OO)技术已经完全占据了最复杂的领域模型。在这本书中,我将有点激进,使用普通函数作为模型领域域行为的主要抽象。在接下来的几节中,您将从建模和维护您的软件的角度看到这样做的好处。
有时,优雅的实现只是一个函数。不是一个方法。不是一个类。不是一个框架。只是一个函数。
------谁说的不重要
让我们从我们过去几年使用的范例开始。在我们样例中,您将剖析一个实现,并逐渐将其转变为一个函数变体。在此过程中,我将强调后者带来的好处。让我们回到我们日常生活中与之互动的领域:个人银行领域。您将考虑一个简单的模型,该模型包含一个聚合的Account,它具有一个值对象Balance、一些其他属性,以及借款和存款的两个操作方法,如下面的清单所示。
清单1.4是自解释的。Account类拥有一个可变状态,即帐户所持有的余额。方法 debit和 credit直接改变对象的状态,以改变帐户在任何时间点上保持的余额。
问:你认为这个模型的主要缺点是什么?
请安静的想一下。如果需要的话可以看看清单1.4。我们将要讨论的可能是为什么你应该领会韩式是思维和建模的最重要的原因之一。
答案:这是一种可通过两种方式影响您的可变性:它使在并发环境中使用抽象变得困难,并且使您很难对代码进行推理。
这里有一个稍微长一点的解释:var balance:Balance在我们的领域模型中一个可变的状态。这里的一个关键词是“mutable(可变)”,这表明这个对象所持有的状态(balance)可以由对象的多个客户端进行更新。在并发环境中这可能导致问题,在任何时候确定这个状态的值,您都可能有各种各样的不一致。这是一个非常大的主题,您可以从优《Java并发编程实战(作者是Brian Goetz,出版于2006)》这本书找到答案。当它涉及到你的代码的推理时,可变状态也是一种反模式,您将在本章后面看到。尽管它在建模世界中似乎是一个令人信服的建模方式,但可变状态产生的问题多于解决方案。您需要找到一种摆脱这些可变状态的方法。
让我们看看是否可以改进以前代码的主要缺点,并保持在面向对象的思维领域。接下来的清单展示我们尝试去净化在清单11.4中由于引进了可变状态带来的错误。
可变状态消失了!在Account上的每一个操作都创建了一个带有修改后状态的新的对象。新的Account类本身带有状态,而不是带有一个可变的状态。一旦你有了这个类的实例,那么在这个实例自身内也就有了balance的一个状态。但不同之处在于这个状态是不可变的。如果不创建另一个Account对象,就无法更改它的值。而这正是debit和credit操作需要做的。Scala确保您在类构造函数中传递的参数默认是不可变的。当然你可以选择一var形式让这些参数可变。但是var也是一个显式的修饰符,标识你需要应用来获得可变性---另一个鼓励不可变抽象设计的优秀决策。
既然您已经将Account变为了一个不可变的抽象,那么在并发模式下,可以自由的在多个线程之间共享它。这是一个巨大的收获,是您第一次领会函数思想的优点的婴儿般的一小步,它的工作原理是,在不依赖或影响任何共享的可变状态下接受输入和生成输出的纯函数。不变性在这里扮演着重要的角色。
但你现在你还没有结束。Account仍然是一种既包含状态又包含行为的抽象。其思想是将两者分离,正如您稍后将看到的那样,这将给您更好的模块性和更好的组合性。但是,如果您使用纯函数对其进行建模的话,让我们首先看看这种代码的优点。