LoginSignup
1
1

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

Last updated at Posted at 2023-09-25

関連記事

はじめに

Salesの中に、MainViewと依存サービスはどのようにデカップリングするのですか? 
今回は、CommandとCallBackを使ってMainViewをリファクタリングします。

@Route("/main")
class MainView extends VerticalLayout {

    // bad smell
    private SalesService salesService;
    // bad smell
    private ProductService productService;
    // bad smell
    private UnderwritingService underwritingService;
    // bad smell
    private ApplicationRecordRepository repository;

    MainView(SalesService salesService,
             ProductService productService,
             UnderwritingService underwritingService,
             ApplicationRecordRepository repository) {

実装

まず、MainViewに関連するビジネスロジックをメソッドにカプセル化する。保険申込を例にとってみましょう。

public UnderWritingResult application(=>?) {
    return underwritingService.application(=>?).getBody();
}

ビジネスパラメーターはコマンドオブジェクトに入れられる。

public UnderWritingResult onApplicationCommand(ApplicationCommand cmd) {
    return underwritingService.application(cmd.getApplication()).getBody();
}

次にアノテーションを追加する。

CommandHandler
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface CommandHandler {

}
@CommandHandler
public UnderWritingResult onApplicationCommand(ApplicationCommand cmd) {
    return underwritingService.application(cmd.getApplication()).getBody();
}

Springの自動注入を使いたかったので、親クラスBaseCommandHandlerを作った。完全なクラスは以下のようになる。

UnderwritingCommandHandler
package com.insurance.life.sales.service;

@Component
public class UnderwritingCommandHandler implements BaseCommandHandler {

    private UnderwritingService underwritingService;

    public UnderwritingCommandHandler(UnderwritingService underwritingService) {
        this.underwritingService = underwritingService;
    }

    @CommandHandler
    public UnderWritingResult onApplicationCommand(ApplicationCommand cmd) {
        return underwritingService.application(cmd.getApplication()).getBody();
    }
}

次に、これらのHandlerを起動時にコンテナに入れる。コンマッドの名前をキーにする。

CommandExecutor
private Map<String, CommandHandlerFunction> context = new HashMap<>();

// handlerList Autowired
public CommandExecutor(List<BaseCommandHandler> handlerList) {
    handlerList.stream().forEach(handler -> {
        Arrays.stream(handler.getClass().getMethods()).forEach(method -> {
            if (method.isAnnotationPresent(CommandHandler.class)) {
                // key
                String commandName = method.getParameterTypes()[0].getName();
                context.put(commandName, (cmd, callback) -> {
                    Object ret = method.invoke(handler, cmd);
                    if (callback != null && ret != null) {
                        callback.callBack(ret);
                    }
                });
            }
        });
    });
}

呼び出すときは、コマンド名を使ってハンドラーを見つける。実行後、結果はCallBackによって呼び出し元に返される。

CommandExecutor
public void execute(Command cmd, CallBack callBack) {
    try {
        context.get(cmd.getClass().getName()).handler(cmd, callBack);
    } catch (InvocationTargetException e) {
        throw new RuntimeException(e);
    } catch (IllegalAccessException e) {
        throw new RuntimeException(e);
    }
}

呼び出し側のコードは以下のようになる。

MainView
// Commandを作成し
ApplicationCommand applicationCommand = new ApplicationCommand(application);
// 実行して
commandExecutor.execute(applicationCommand, (CallBack<UnderWritingResult>) result -> {
    // CallBack
    if (result.isPass()) {
        doSomething...
    } else {
        doSomething...
    }
});

注入されたさまざまなサービスは、汎用コンポーネントで置き換えられる。

MainView
@Route("/main")
class MainView extends VerticalLayout {

    private CommandExecutor commandExecutor;
    // 【消えた】private SalesService salesService;
    // 【消えた】private ProductService productService;
    // 【消えた】private UnderwritingService underwritingService;
    // 【消えた】private ApplicationRecordRepository repository;


    MainView(CommandExecutor commandExecutor) {
        this.commandExecutor = commandExecutor;

以上です。

Source Code

終わり

誰も[いいね]をくれないので、ちょっと休んでまた書くよ。

1
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
1
1