在系统论中,控制 是处理大型复杂系统最有用的方式之一。在软件开发行业,控制或封装的价值很容易理解。可通过编程语言的子程序,函数,模块,包,类等进行控制。
模块和包用于解决更大规模的封装需求,而类,函数等用于解决更细粒度的封装需求。过去这些年我意识到类层次的封装似乎成为了开发者最难封装的结构。 找出一个类中main方法包含3000行代码的类并不常见,或一个类仅有属性和对应的get/set方法。这些示例证明开发者并没有完全理解面向对象思想,在利用面向对象建模方面是失败的。
一个对象既要封装状态,也要封装行为。 其中的行为由实际的状态定义。考虑一个“门”对象,由四个状态,分别对应:已打开,已关闭,打开中,关闭中。它提供两种操作:打开和关闭。依赖当前状态的不同,打开和关闭操作的表现也不同。对象的这种固有特性使设计过程在概念上变得简单。它归结为两个简单任务:分配和委派责任给不同的对象(包括对象间交互协议)。
这在实践中如何生效,需要一个示例来说明。假设我们有三个类:Customer, Order, 和Item,一个Customer对象自然具有了信用额度和信贷规则。一个Order对象会跟某个Customer关联,并且它的添加操作(addItem)会委托给实际的信用检查来执行: customer.validateCredit(item.price())。
而缺乏面向对象开发经验的开发者会倾向于将所有的业务逻辑写到一个对象中,通常会命名为OrderService,在此设计中Customer, Order,Item都被退化为记录类型,所有的逻辑被排除在了这些类之外,绑在一起形成一个大的过程化的方法,这些方法充斥着大量的 if-then-else结构,且极不稳定和难以维护。为什么会这样?是封装性被破坏了。
小结
类不仅只封装状态,也需要封装行为,需要满足OOP设计时的目标:从业务中建模抽象独立的个体,通过互相发送消息(方法调用)的方式组成庞大的系统。反过来只封装行为也不对,这样就成了一个个贫血对象。