関連記事
はじめに
今回は、保険料の計算を実装する。保険料入力枠にフォーカスが当たると、自動的に保険料が計算されます。
アイデア
保険商品によって保障内容が異なり、保険料の計算も異なる。それでも、商品サービスの高い凝集性と単一責任の考え方に従って、Strategyパターンを使って保険料の計算を実装する。
- P001 安心医療 => 料率表を使って保険料を計算する。
- P002 安心年金 => 固定レートを使用して保険料を計算する。
新商品の保険料計算が既存のStrategyに一致する場合、そのStrategyを再利用することで開発をスピードアップできます。
実装
料率表を使って保険料を計算する
PremiumCalculateWithTable
@Component
public class PremiumCalculateWithTable implements PremiumCalculate {
@Override
public BigDecimal calculate(PremiumCalculateRequest request) {
Rate rate = rateRepository.findByProductIdAndAgeAndGender(
request.getProductId(), request.getAge(), request.getGender());
return request.getAmount().multiply(rate.getRate()).setScale(0, RoundingMode.CEILING);
}
}
固定レートを使用して保険料を計算する
PremiumCalculateWithFixedRate
@Component
public class PremiumCalculateWithFixedRate implements PremiumCalculate {
@Override
public BigDecimal calculate(PremiumCalculateRequest request) {
return request.getAmount()
.divide(new BigDecimal(request.getTerm()), RoundingMode.HALF_DOWN)
.multiply(new BigDecimal(1.10))
.setScale(0, RoundingMode.CEILING);
}
}
Strategyのロード
起動時に PremiumCalculateStrategyFactory に strategy をロードします。
PremiumCalculateStrategyFactory
package com.insurance.life.product.service.strategy.premium;
@Component
public class PremiumCalculateStrategyFactory {
private Map<String, PremiumCalculate> strategyMap;
public PremiumCalculateStrategyFactory(List<PremiumCalculate> strategies) {
strategyMap = strategies.stream()
.collect(Collectors.toMap(PremiumCalculate::getName, x -> x));
}
// Strategy をその名前で呼び出します。
public PremiumCalculate getStrategy(String name) {
return strategyMap.get(name);
}
}
Config
Config で商品に使用する特定strategyを設定する。
Config
package com.insurance.life.product.entity;
@Entity
public class Config implements Serializable {
...
private int minAge;
private int maxAge;
// Strategy名前
private String premiumCalculateStrategyName;
...
}
Strategyの呼び出し
商品の初期化
Config config = new Config(18, 60,
new BigDecimal(300000),
"PremiumCalculateWithTable", // Strategy名前
Arrays.asList(Term.YEAR_1, Term.YEAR_3, Term.YEAR_10, Term.YEAR_20),
Arrays.asList(PaymentType.TYPE_MONTH));
Product product = new Product("P001", "安心医療", config);
repository.save(product);
料率表の初期化
private void initRate() {
rateRepository.deleteAll();
Rate rate;
for (int i = 10; i < 80; i++) {
rate = new Rate("P001", i, "F",
new BigDecimal(1 + i/1000.0).divide(
new BigDecimal(100), RoundingMode.HALF_DOWN).setScale(6, RoundingMode.HALF_DOWN));
rateRepository.save(rate);
rate = new Rate("P001", i, "M",
new BigDecimal(1.1 + i/1000.0).divide(
new BigDecimal(100), RoundingMode.HALF_DOWN).setScale(6, RoundingMode.HALF_DOWN));
rateRepository.save(rate);
}
}
Source Code
終わり
機能が増えれば、Bad Smellも増える。
- MainViewと依存サービスはどのようにデカップリングするのですか?
- 重複するDTO、最適化するには?
- RestApi宣言はどのように最適化できるか?
最後まで読んでいただきありがとうございました。何かご提案やご質問がありましたら、コメントをお待ちしています。