实体应该有行为吗?或不?
为什么或者为什么不?
如果没有,那是否违反了封装?
如果您的实体没有行为,那么您不会编写面向对象的代码.如果所有内容都是使用getter和setter完成而没有其他行为,那么您正在编写过程代码.
许多商店表示,当他们保持实体愚蠢时,他们正在练习SOA.他们的理由是数据结构很少改变,但业务逻辑确实如此.这是一个谬论.有很多模式可以解决这个问题,而且它们并不涉及将所有东西都减少到吸气剂和固定剂袋中.
实体不应有行为。它们代表数据,数据本身是被动的。我目前正在从事一个遗留项目,该遗留项目已将实体的行为纳入其中,这是一场噩梦,没人想碰代码。
您可以在我的博客文章:面向对象的反模式-具有行为的数据对象上阅读更多内容。
属性和行为
对象由属性和行为组成,但是数据对象从定义上仅代表数据,因此只能具有属性。书籍,电影,文件,甚至IO流都没有行为。一本书有标题,但不知道如何阅读。电影有演员,但不知道怎么玩。文件包含内容,但不知道如何删除。流具有内容,但是它不知道如何打开/关闭或停止。这些都是具有属性但没有行为的数据对象的示例。因此,应将它们视为愚蠢的数据对象,而我们作为软件工程师不应将行为强加于它们。
传递数据而不是行为
数据对象在不同的执行环境中移动,但是行为应该被封装,并且通常只与一个环境有关。在任何应用程序中,数据都会被传递,解析,操纵,持久化,检索,序列化,反序列化等等。例如,实体通常从休眠层传递到服务层,再传递到前端层,然后再返回。在分布式系统中,它可能会通过多个管道,队列,缓存并最终进入新的执行上下文。属性可以应用于所有三个层,但是特定的行为(例如保存,解析,序列化)仅在各个层才有意义。因此,向数据对象添加行为会违反封装,模块化甚至安全原则。
代码如下:
book.Write(); book.Print(); book.Publish(); book.Buy(); book.Open(); book.Read(); book.Highlight(); book.Bookmark(); book.GetRelatedBooks();
可以这样重构:
Book book = author.WriteBook(); printer.Print(book); publisher.Publish(book); customer.Buy(book); reader = new BookReader(); reader.Open(Book); reader.Read(); reader.Highlight(); reader.Bookmark(); librarian.GetRelatedBooks(book);
自然的面向对象建模可以带来多大的不同!我们从单一的怪异的Book类转变为六个独立的类,每个类负责各自的行为。
这使代码:
更自然,更易于阅读和理解
更容易更新,因为功能包含在较小的封装类中
更加灵活,因为我们可以轻松地用覆盖版本替换六个单独类中的一个或多个。
由于功能是分开的,因此更易于测试,并且更易于模拟