从贫血模型到充血模型


本文转载自【何以解耦】:codedecoupled.com/anemic-domain-mo...

领域模型

领域模型是一种用于解决复杂业务逻辑的建模工具/思想。大神 Martin Fowler 定义其为包含行为和数据的对象模型。

使用领域模型时,我们的目标是建立丰富的充血领域模型,但由于某种原因,一种不被提倡的模式(贫血模型)被广泛使用。

贫血领域模型

贫血模型是一种众所周知的反模式(anti-pattern),但是要摈弃这种思想却不是简单的事情。因为这种设计开发迅速,易于理解。不经意间,它就可能出现在我们的代码中。

举个例子,我们的应用中有一个激活用户功能:

class User extends OrmModel
{
    public setStatus($status)
    {
        $this->status = $status;
    }

    public getStatus()
    {
        return $this->status;
    }
}

class UserService
{
   public activate(User $user)
   {
           if ($user->getStatus() === 'blacklisted') {
               throw new \Exception('User is blacklisted');
           }

         $user->setStatus('active');
         $user->save();
   }
}

乍一看,这种模式有模有样:数据库表通过映射建造一些 ORM 类,各类之间存在一定的关系,而且还使用了服务层(Service layer)进行分层管理。

但是让我们仔细想想。User 类无非一些 getter 和 setter,符合了领域模型包含数据的标准,却缺失了最重要的部分:行为。而将业务逻辑放入服务类(Service class)中,形成了一种类似于事务处理脚本的面向过程的编程方式,与领域模型所倡导的面向对象编程背道而驰。一个健康的服务层应该是很薄的,其主要职责是调用充血的领域模型完成业务流程。

这种贫血模型建立在领域模型的成本上,却没有带来领域模型的好处。

充血领域模型

充血领域模型是领域模型所提倡的建模方式。顾名思义,充血领域模型是包含行为和数据的对象模型。

举个例子,上文中的激活用户功能:

class User extends OrmModel
{
    public function activate()
    {
        if ($user->status === 'blacklisted') {
               throw new \Exception('User is blacklisted');
           }
           $this->status = 'active';
    }
}

class UserService
{
   public function activate(User $user)
   {           
         $user->activate();
         $user->save();
   }
}

一个完善的充血领域模型能降低 Bug 风险,帮助我们更直观的建立业务模型。

建立充血领域模型需要开发者具备良好的面向对象思想。能够准确划分服务层逻辑和领域层(Domain Layer)逻辑。
经验法则是,在建立服务层时候,业务逻辑应被封至领域层,事务逻辑封装应被封至服务层,因此服务层应该是很薄的。此处的薄不能完全代表代码量,而是指业务逻辑含量。

对症下药

领域模型的目的是简化一个复杂的问题,而不是将一个简单的问题复杂化。正如 Martin Fowler 所说,领域模型并非包治百病的灵丹妙药,开发者在解决问题时还需对症下药:

从贫血模型到充血模型

如果你处理的问题使用增删改查即可完成,那么使用譬如 Active Record 这种数据驱动模式才是更适宜的方案。使用领域模型来解决简单的 CURD 问题,那就成了牛刀割鸡,得不偿失。

本文转载自【何以解耦】codedecoupled.com/anemic-domain-mo... ,如果你也对 TDD,DDD 以及简洁代码感兴趣,欢迎关注公众号【何以解耦】,一起探索软件开发之道。

本作品采用《CC 协议》,转载必须注明作者和本文链接
Know how, know why meanwhile.
xuding
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 8
aab

裤子都脱了你就给个这

2年前 评论

我看看有没有兄弟和我一样 兴冲冲的进来的

2年前 评论
xuding (楼主) 2年前
抄你码科技有限公司

:scream: 你们都充血了吗!

2年前 评论

老板不管你充血贫血,他只要你出血

2年前 评论
QIN秦同学
还是一脸懵逼,案例还能再细致点么?
看极客的《设计模式之美》,phper 理解 充血和贫血 确实难呀。
2年前 评论
July-Y 2年前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!