封装行为,而不仅仅是状态

Encapsulate Behavior, not Just State

在系统理论中,包含是处理大型复杂系统结构的最有用的架构之一。在软件工程领域,包含和封装的价值已被认可。编程语言的架构,包含通过如子程序和函数、模块、包、类等方式来得到支持。

模块和包用于处理更大层面的封装需求,而类、子程序、函数则处理更多细节层面的事情。近些年我发现,类似乎成了开发人员最难封装的结构之一。一个类拥有3000多行的main方法,或者一个类仅有set/get方法用于它的原始属性的情况并不罕见。这些例子说明开发者还没有充分理解面向对象思想,没有发挥对象建模的优势。对于开发者熟悉的术语POJO以及POCO(Plain Old Java/C# Object),这相当于模型的范例,回归到了面向对象的基础——对象是朴实而简单的,但不是哑巴!

(译注: POJO是指仅有属性及其get/set方法的类,没有任何业务行为,常用于数据库的实体映射,在DDD中是典型的贫血模型)

一个对象要同时封装状态和行为,其中行为由实际的状态定义。设想一个“门”对象。它有四种状态:关着、开着、关上、打开。它提供了两种操作:开和关。基于这些状态,开和关操作将产生不同行为。一个对象的内在特性使得设计过程在概念上变得简单。可以归结为两个简单的任务:给不同的对象分配和委托职责,包括对象间的通信协议。

通过一个例子可以最好的说明在工作中要如何运用。让我们设想有三个类:Customer, Order, 和Item。Customer对象是信用限额与信用验证规则的天然占位符。一个Order对象知道它和Customer的关系,它的addItem操作通过调用customer.validateCredit(item.price())委托实际的信用验证。如果这个方法的后置条件失败,抛出异常并终止交易。

经验不足的面向对象开发者可能会决定把所有的业务规则打包到通常称为OrderManagerOrderService的对象当中。在这些设计中,Order,Customer,Item被用作记录类型。所有的逻辑都是从类里分解出来并捆绑在一个大的、有大量if-then-else构成的程序方法内。这些方法很容易被破坏,而且几乎不可能维护。原因?封装被破坏了呀。

0%