0
1

ミニ生命保険システムを作成 S07

Last updated at Posted at 2023-09-23

関連記事

はじめに

今回はUnderwriting中に様々なルールを実装します。デザインパターンにおける単一責任、テンプレートメソッドを理解する必要がある。また、ロジックとデータの分離という考え方も理解しておく必要がある。
undw.png

実装

単一責任

保険システムに様々なルールがあります。ルールの実装が混在すると、システムのメンテナンスが非常に難しくなる。そこで、1つのルールと1つのクラスで実装する。各ルールにはビジネスチェックが1つだけ含まれる。例えば、被保険者の年齢のチェック。

InsuredAgeRule
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;
    }
}

テンプレートメソッド

ルールが実行されると、まず、実行する必要があるかどうかがチェックされる。 その後、実際のビジネスロジックが実行される。 次に、このステップを親クラスに抽出し、テンプレートメソッドを形成します。

Rule
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 

sql.png

ロジックをデータから切り離し、新しい商品を追加するときはデータを追加するだけでロジックを再利用することができます。

InsuredAgeRule
    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を追加しました。プロジェクトのインポートが簡単になりました。

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 つのフレームワークはドメインレイヤーでは役に立ちません。

最後まで読んでいただきありがとうございました。何かご提案やご質問がありましたら、コメントをお待ちしています。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1