関連記事
はじめに
今回はUnderwriting中に様々なルールを実装します。デザインパターンにおける単一責任、テンプレートメソッドを理解する必要がある。また、ロジックとデータの分離という考え方も理解しておく必要がある。
実装
単一責任
保険システムに様々なルールがあります。ルールの実装が混在すると、システムのメンテナンスが非常に難しくなる。そこで、1つのルールと1つのクラスで実装する。各ルールにはビジネスチェックが1つだけ含まれる。例えば、被保険者の年齢のチェック。
public class InsuredAgeRule extends Rule {
private ProductService productService;
public InsuredAgeRule(ProductService productService) {
this.productService = productService;
}
@Override
String getMessage(Object... params) {
return "被保険者の年齢は%d歳以上%d歳未満である必要がある。".formatted(params);
}
@Override
public boolean needCheck(Application application) {
return true;
}
@Override
public UnPassedReason doCheck(Application application) {
...
return unPassedReason;
}
}
テンプレートメソッド
ルールが実行されると、まず、実行する必要があるかどうかがチェックされる。 その後、実際のビジネスロジックが実行される。 次に、このステップを親クラスに抽出し、テンプレートメソッドを形成します。
public abstract class Rule {
abstract String getMessage(Object ... params);
abstract boolean needCheck(Application application);
abstract UnPassedReason doCheck(Application application);
// テンプレートメソッド
public final UnPassedReason check(Application application) {
if (needCheck(application)) {
return doCheck(application);
} else {
return null;
}
}
}
ロジックとデータの分離
被保険者の年齢を例にとると、保険商品によって被保険者の年齢条件は異なる。 では、商品別にルールを追加すべきなのだろうか?
if ("P001"の場合) {
check()
}
if ("P002"の場合) {
check()
}
そんなことをすれば、ルールはますます多くなり、汎用的ではなくなってしまう。 商品はすでに設定されていることをお忘れなく。
SELECT A.ID,A.NAME,B.MAX_AGE,B.MIN_AGE
FROM PRODUCT A, CONFIG B
WHERE A.CONFIG_ID = B.ID
ロジックをデータから切り離し、新しい商品を追加するときはデータを追加するだけでロジックを再利用することができます。
public UnPassedReason doCheck(Application application) {
ConfigDTO config = productService.getConfig(
application.getPlanList().get(0).getProductId()).getBody();
UnPassedReason unPassedReason = null;
if (application.getInsured().getAge() < config.getMinAge()
|| application.getInsured().getAge() > config.getMaxAge()) {
unPassedReason = new UnPassedReason("R0002",
getMessage(config.getMinAge(),config.getMaxAge()));
}
return unPassedReason;
}
ルールの実装を完了しました。ほとんどのルールはこの方法で実装できる。
Source Code
ソースコードの修正
Github中にソースコードを修正しました。pom.xmlを追加しました。プロジェクトのインポートが簡単になりました。
</project>
...
<name>Mini Insurance App</name>
<modules>
<module>eureka</module>
<module>gateway</module>
<module>product</module>
<module>underwriting</module>
<module>underwriting-api</module>
<module>sales</module>
</modules>
</project>
終わり
現在、システムは少し複雑になっている。レイヤー間のデータ転送については、まだ少し混乱がある。貧血モデルを使用の場合、LombokとModelMapperは非常に便利です。しかし、DDD充血モデルを使用すると、これら 2 つのフレームワークはドメインレイヤーでは役に立ちません。
最後まで読んでいただきありがとうございました。何かご提案やご質問がありましたら、コメントをお待ちしています。