#参照関係
SalesforceでDDDを実現した場合の参照関係は以下のようになります。
######インフラ層(オレンジ)
DBや外部APIに接続する部分になります。
DAOもこちらに該当します。
######ドメイン層(グリーン)
システムにおける知識を持ったクラスが該当します。
ドメイン層は二つに分けられます。
・ドメインモデル
⇒ふるまい・ルールを持ったオブジェクト
・ドメインサービス
⇒ドメインモデルで表し切れない処理をここに書く
SalesforceにおいてはsObjectが最もドメインモデルに近いかと思います。
なので、ドメインモデルクラスは作りません。
ドメインサービスはsObjectを補助するようなクラスにします。(バリデーションチェックなどが該当)
######アプリケーション層(ブルー)
ここではシステムにおけるユースケースに対応するクラスが該当します。
######UI/Batch/Trigger/GlobalAPI層(グレー)
ユースケース処理を呼ぶクライアント層になります。
Salesforceでは、UI(Visualforce・LightningComponent等)、Batch、Trigger、GlobalAPI(Apexの外部公開カスタムAPI)が該当します。
######高レベルから低レベルへ依存させる
依存は高レベル(より人間に近い動き)から低レベル(より機械に近い動き)に参照させます。
それぞれのパターンから入ってきたユースケースを低次元の処理を使って解決させていきます。
#サンプルアプリ
######要件
■Contact Create Page
・Contactレコードが作成できる
・「Account Phone」が同じAccountレコードが既に存在している場合は、そのレコードをContactレコードに紐づける
・「Account Phone」が同じAccountレコードがない場合は、作成してそのレコードをContactレコードに紐づける
■Contact Table
・Contact Create Pageで作成したレコードが表示される
#クラス構成
以下がサンプルアプリのソースコードです。
https://github.com/MASA-JAPAN/Salesforce-DDD-Template
#処理概要
■Contact Create Page
LWCフレームワークで開発しております。
コントローラ(dddContactCreateController.cls)は一番上のグレー層に該当します。
こちらからContactApplicationService(アプリケーション層)のユースケース処理(createNewDddContact)を呼びます。
public with sharing class dddContactCreateController {
public dddContactCreateController() {
}
@AuraEnabled
public static String clickAction( String AccountName, String AccountPhone, String LastName, String FirstName ){
ContactApplicationService contactAppService = new ContactApplicationService();
return contactAppService.createNewDddContact(AccountName, AccountPhone, LastName, FirstName);
}
}
createNewDddContactでは、ドメイン層(sObjectとObjectService層)とインフラ層(DAO)を駆使してユースケースを実現してます。
public Id createNewDddContact( String AccountName, String AccountPhone, String LastName, String FirstName ){
//If there is not an Account record, create it.
AccountService accountService = new AccountService();
Account targetAccount = new Account( Name = AccountName, Phone = AccountPhone );
List<Account> sameAccounts = new List<Account>( accountService.getSameAccount(targetAccount) );
if( sameAccounts.size() == 1){
targetAccount = sameAccounts[0];
} else if( sameAccounts.size() == 0 ){
insert targetAccount;
} else {
throw new ContactApplicationServiceException('Phone ' + AccountPhone + ' is duplicated' );
}
Contact contact = new Contact(AccountId = targetAccount.Id, LastName = LastName, FirstName = FirstName, LeadSource = 'DDD' );
insert contact;
return contact.Id;
}
さらに詳しくはGithubのソースコードを見て頂ければと思います。
#まとめ
ざーっと書いてみました、まだまだブラッシュアップすべき点は満載です!
是非コメント頂けると嬉しいです。