1. 程式人生 > >ddd的戰術篇: application service, domain service, infrastructure service

ddd的戰術篇: application service, domain service, infrastructure service

之前的一篇文章談到了貧血模型,而ddd是提倡充血模型的,即儘量把邏輯寫在domain object中,而不是寫一大堆的service類,對資料類進行操作。那麼為什麼ddd裡會有service類呢?這篇文章會對service進行說明。

ddd中的service

首先這個在這篇文章裡討論的service基於一個前提,就是採用view, application, domain, infrastructure的分層架構。ddd提倡的架構有很多種,大家可以看前面的文章。《domain driven design》原書也是基於分層架構來論述的。至於現在流行的洋蔥架構該怎麼辦,有機會再講吧~
ddd中有三種service。分別是application service, domain service, infrastructure service。

application service

首先從簡單的開始講。application service是應用程式的某個功能的入口(end point)。如果你使用的是分層架構,那它是位於presentation和domain之間。
我們想像我們要寫一個api用來註冊賬號。
url: api/accounts
method: post
如果我們使用springMVC來實現這個api的話,那Controller會呼叫AccountApplicationService。

@RestController
@RequestMapping("api/accounts")
public class
AccountController{
@Autowired private AccountApplicationService accountApplicationService; @RequestMapping(value ="", method = RequestMthod.POST) public void register(@RequestBody AccountDTO accountDTO){ accountApplicationService.register(accountDTO); } }

上面的程式碼,controller講畫面傳過來的dto傳給了AccountApplicationService。
AccountApplicationService再來呼叫各種domain object。比如Account (entity), AccountRepository。

public class AccountApplicationService {
    @Autowired
    private IAccountRepository accountRepository;

    public void register(AccountDTO accountDTO){
        Account account = Account.createAccount(accountDTO.getEmail(), accountDTO.getPassword());
        accountRepository.save(account);
    }
}

infrastructure service

infrastructure service實現不依賴於業務(domain)的功能。簡單的例子來講,比如列印日誌(log),傳送郵件(如果你的應用軟體不是處理郵件問題的話)
infrastructure service位於最底層的infrastructure層。

domain service

實現domain的service類。三種service中,唯一可以寫業務邏輯的地方。
由於ddd提倡充血模型的緣故,我們在建模的時候要儘量避免製造domain service。儘量把業務邏輯放到其他的domain object中(比如entity, value object中)。

Service的比較

application service vs domain service

我想infrastructure是沒有什麼值得討論的。而application service與domain service會是讓人糾結的一個話題。
最近看到了clean architecture的設計後,感覺可能稍微容易解釋一些。(對不起,說好用只討論分層架構的,卻又提起了clean architecture,因為好難解釋…)
這裡寫圖片描述
entities的部分對應的便是domain部分。
而application service對應的是use cases 用例。
相比於application service這個有點不知所云的名次,用例是不是更容易理解一些了(也許不是。。。)?
用例
用uml圖來畫的話,就是下面這樣的東西。
這裡寫圖片描述
用例具體教科書般的定義,大家可以自行谷歌一下。大致就是描述一個系統大致的功能而並不描述具體內部的結構或者設計。
那在clean architecture中,domain object的操作必須通過「用例」這個入口。

那在操作層面上如何處理application service和domain service呢?

首先application service既然是入口,在一個模組中,它必定是存在的。與之相反,domain service則不一定需要。
因此,再做類設計時可以先假定domain service不存在。直接寫application service,在application service中對其他domain object進行操作。
理想情況下,application service存在的程式碼基本上就是它呼叫其他domain object的方法,具體的業務邏輯都會在domain object的方法中。所以當application service中出現if/else之類的語句,或者application service的一個方法變得很長時,我們就該警惕是不是把業務邏輯寫到了application service中。這個時候我們該考慮是否需要重構,比如把邏輯放進domain object,或者增加一個domain service。
按上面一個註冊賬號的例子,這個時候我們並不需要domain service。
但如果我們首先要確認email是否被註冊,那這時候程式碼就會變成下面那樣

public class AccountApplicationService {

    @Autowired
    private IAccountRepository accountRepository;

    public void register(AccountDTO accountDTO){
        Account account = accountRepository.find(new AccountSpecificationByEmail(accountDTO.getEmail()));
        if (account != null) {
            throw new EmailAlreadyRegisteredException();
        }
        account = Account.createAccount(accountDTO.getEmail(), accountDTO.getPassword());
        accountRepository.save(account);
    }

}

儘管方法不是很長,但判斷賬號能否被註冊的邏輯(業務邏輯)寫在了application service中。我們必須考慮將這個邏輯移到其他地方。
當然理想情況下是把它放進Account中,但查詢賬號是否存在的邏輯使用到AccountRepository,這個很難放進Account中,所以AccountService自然會是一個選擇。

public class AccountService {

    @Autowired
    private IAccountRepository accountRepository;

    public void register(String email, String password){
        Account account = accountRepository.find(new AccountSpecificationByEmail(email));
        if (account != null) {
            throw new EmailAlreadyRegisteredException();
        }
        account = Account.createAccount(email, password);
        accountRepository.save(account);
    }
}

因為不想讓domain層的東西依賴於application層的form,dto類,所以方法的引數沒有用dto。
那application service會變成

public class AccountApplicationService {

    @Autowired
    private AccountService accountService;

    public void register(AccountDTO accountDTO){
        accountService.register(accountDTO.getEmail(), accountDTO.getPassword());
    }

}

另外,有了AccountService這個類,並不是所有關於Account的邏輯都必須放進那裡。
比如AccountApplicationService裡的changePassword(),沒有必要放進AccountService中。

public class AccountApplicationService {

    @Autowired
    private IAccountRepository accountRepository;
    @Autowired
    private AccountService accountService;

    public void register(AccountDTO accountDTO){
        accountService.register(accountDTO.getEmail(), accountDTO.getPassword());
    }

    public void changePassword(String email, String oldPassword, String newPasssord) {
        Account account = accountRepository.findById(email);
        account.changePassword(oldPassword, newPasssord);
        accountRepository.save(account);
    }

}

總結

ddd中把service類分成三種。
application service, domain service, infrastructure service。
domain service中可以寫業務邏輯,但同時理想情況下我們儘量不實用domain service。
另外,我們要注意不要講業務邏輯寫到application service中。

相關推薦

ddd戰術: application service, domain service, infrastructure service

之前的一篇文章談到了貧血模型,而ddd是提倡充血模型的,即儘量把邏輯寫在domain object中,而不是寫一大堆的service類,對資料類進行操作。那麼為什麼ddd裡會有service類呢?這篇文章會對service進行說明。 ddd中的servic

ddd戰術: domain object之一

首先ddd的戰術這個講法是不太好的。ddd書中說的是戰術性建模(tactical modeling)。其意思是在戰術層面的建模,那當然有戰略層面的建模啦。以後會專門講。 domain object是ddd區別於其他建模/設計方法的一個部分。他定義了概念幫助我們去建立mo

java service domain dao 分層思路

兩個 活動 通過 操作 變化 根據 ron 類型 返回 今天在開發項目的時候,對項目的java後臺的分層有一些看法: 首先,鼓勵使用service domain dao 層分層設計概念。 其次,對幾層作用的理解: 第一:dao層操作單表,不涉及復雜邏輯,主要是表的增刪改

如何在SAP Cloud Application Studio裡建立Web Service

I woud like to change this extension field in third party system outside C4C, using web service or OData service. I have created a new action

Access GSuite APIs on your domain using a service account

Access GSuite APIs on your domain using a service accountThis tutorial provides a step-by-step guide to creating a service account that has delegated domai

How to Deploy a Kubernetes Application with Amazon Elastic Container Service for Kubernetes

This tutorial shows you how to deploy a containerized application onto a Kubernetes cluster managed by Amazon Elastic Container Service

ddd戰術: aggregate的設計策略

上一篇文章講了repository的實現。結合前面的文章基本把ddd戰術篇中的登場人物都介紹了一遍。依次是如下幾個角色。 首先是位於domain層的domain objects - aggregate - entity - value object

就夠了系列之Service全解析

前言: 一篇就夠了系列之Activity全解析中詳細介紹了Activity的相關知識點,感興趣的同學可以看看。本篇文章主要介紹下Service的一些學習感悟,希望能對大家有所幫助。 下面從以下四個部分開展: Service基礎 Service兩種啟動方式

ADF 第三:Integration runtime和 Linked Service

Azure Data Factory 系列部落格: ADF 第一篇:Azure Data Factory介紹 ADF 第二篇:使用UI建立資料工廠 ADF 第三篇:Integration runtime和 Linked Service   Integration runtime(IR) 是Azu

How to Remove A Service Entry From Win10 Service List

console hot list warn oba tor div register ever .warnbanner { width: 600px; background-color: #FFEFCE } .warnbanner.border { border: 0px

Android Service、IntentService,Service和元件間通訊

Service元件 Service 和Activity 一樣同為Android 的四大元件之一,並且他們都有各自的生命週期,要想掌握Service 的用法,那就要了解Service 的生命週期有哪些方法,並且生命週期中各個方法回撥的時機和作用 什麼是service?service的基本概念 Servic

Service和IntentService,Service和Activity之間通訊

Service /** * Android四大元件之一,Service 是長期執行在後臺的應用程式元件。 * Service 不是程序,也不是執行緒,它和應用程式在同一個程序中 * Service中不能

springboot專案下,service層注入其他service時,沒有新增@Autowired,專案中不報錯,就是報空指標

這個問題讓我折騰了快一天,因為這個方法是個通用方法,在別的service都能執行成功,就是在此service下執行不成功, 無意間發現了@autowired註解沒有加,協同開發不知道誰不小心刪除了吧。但是springboot也不報錯, try...catch後總是報空指

ubuntu 16.04 boot 啟動報錯 dns-clean.service 、plymouth-quit.service

ubuntu 16.04 boot 啟動報錯 1,ubuntu系統版本 2,dns-clean.service 報錯 3,plymouth-quit.service報錯,待解決 1,ubuntu系統版本 # lsb_release

Android學習筆記(五三:服務Service(下- Remote Service

之前所談的Service屬於Local Service,即Service和Client在同一程序內(即同一application內),Service的生命週期服從程序的生命週期。在實際應用上,有時希望Service作為後臺服務,不僅被同一程序內的activity使用,也可被其他程序所使用,針對這種情況,需要採

Android-Service元件之Bound Service

bound service是工作在客戶端/服務端模式的service。bound service允許別的元件繫結到service上,然後傳送請求、接收響應、甚至是做跨程序的IPC操作。bound service只有在它為別的元件提供服務的時候才是存活的,並且不會在後臺無

40-Service學習第一發Service的生命週期

1.Android中使用Service的目的:後臺執行和跨程序訪問。 2.Service中的生命週期有三種:建立服務、開始服務、銷燬服務 3.Service生命週期對應的三個方法:onCreate()\onStart()\onDestory() 4.服務和Activity一

spring註解@service("service")括號中的service有什麼用

service  是有用的相當於 xml配置中得bean  id = service  也可以不指定 不指定相當於 bean id =  com. service.service 就是這個類的全限定名,表示給當前類命名一個別名,方便注入到其他需要用到的類中;不加的話,預設

Building a Continuous Delivery Pipeline for AWS Service Catalog (Sync AWS Service Catalog with Version Control)

AWS Service Catalog enables organizations to create and manage catalogs of IT services that are approved for use on AWS. These IT services can inc

[外一]關於Unix Domain Socket

咋一看名字,雖然有個socket,但是它的用場和常說的“網路”socket有所不同。它實際上是一種本地IPC,以socket為名是因為它和普通socket使用的介面是一致的。 雖說普通的socket也可以用作本地IPC,但是從效率上和功能上,要遜於Unix Domain