実業務で使うオブジェクト指向（個別処理呼び出し）

# この記事は？
オブジェクト指向を実業務でどう使うのかって話、その１。
個別処理の実装時に、呼出元を修正しなくてよくなるよ。

# 想定環境
* Java
* Spring Boot
* Mybatis

# 実装
:::note warn
業務で実装したコードを、退職後に思い出しながら手打ちしている
:::
:::note warn
継承に関するところを主として記載しているため、本番運用で考慮すべき事項に対応してない（テーブルの内容やBeanのキャッシュ、エラーハンドリングなど）
:::

### 個別処理用の基底クラス
```Java:BaseExecutor.java
public abstract class BaseExecutor {
    /**
     * 個別処理対象の判定。
     * @param args 処理に使用するパラメータ配列。
     * @return 個別処理対象の場合true、そうでなければfalse。
     */
    public boolean executable(Object args...) {
        return true;
    }
    /**
     * 個別処理。
     * @param args 処理に使用するパラメータ配列。
     * @return 個別処理結果のレスポンスエンティティ。
     */
    public abstract ResponseEntity<?> execute(Object args...);
}
```

### サービスの基底クラス
```Java:BaseService.java
public class BaseService {
    /** コンテキスト */
    @Autowired ApplicationContext appContext;

    /** 個別処理マスタ */
    @Autowired IndividualProcessesMapper individualProcessesMapper;

    /**
     * 個別処理呼び出し処理。
     * @param procKey 処理キー。
     * @param args 処理キーに対応した処理に使用するパラメータ配列。
     * @return 個別処理結果のレスポンスエンティティ。
     */
    protected ResponseEntity<?> callProcess(String procKey, Object args) throws Exception {
        ResponseEntity<?> entity = null;

        // 個別処理マスタを参照
        // IndividualProcessはproc_key, bean_nameを持つテーブルのエンティティ
        List<IndividualProcess> procs = this.individualProcessesMapper.findAll(procKey);
        for(IndividualProcess proc : procs) {
            String beanName = proc.getBeanName();

            // 個別処理
            BaseExecutor exec = (BaseExecutor) this.appContext.getBean(beanName); // (1)
            if(exec.executable(args)) {
                entity = exec.execute(args);
                break;
            }
        }

        return entity;
    }
}
```
オブジェクト指向の利用において、肝となるのは (1) の部分。
個別処理マスタに登録されているbean名で任意のbeanを取り出せるので、呼出元になるサービスクラスを修正することなく、個別処理を追加することができる。

個別処理を追加することになった場合は、とりあえずBaseExecutorを継承するbeanを作って、個別処理マスタにbean名を登録しておけばいい。

# 利用例
ここでは以下を例とする。
* 指示情報を取得するAPIがある
* クエリパラメータのorderTypeがwmsだった場合、個別処理として外部システムと連携する
* クエリパラメータのorderTypeがawsだった場合、個別処理としてクラウドサービスと連携する
* 上記以外の場合は標準処理としてシステム内部の指示情報を応答する
### 個別処理1
```Java:WmsOrdersGetExecutor.java
@Component
public class WmsOrdersGetExecutor extends BaseExecutor {
    /**  */
    protected final String ORDER_TYPE = "wms";
    /**  */
    public boolean executable(Object args...) {
        String orderType = args[0];
        if(ORDER_TYPE.equals(orderType)) {
            return true;
        }
        return false;
    }
    /**  */
    public ResponseEntity<?> execute(Object args...) {
        // ...個別処理...
        return entity;
    }
}
```
### 個別処理2
ORDER_TYPEの値以外、個別処理1と同様
```Java:AwsOrdersGetExecutor.java
@Component
public class AwsOrdersGetExecutor extends BaseExecutor {
    /**  */
    protected final String ORDER_TYPE = "aws";
    /**  */
    public boolean executable(Object args...) { ... }
    /**  */
    public ResponseEntity<?> execute(Object args...) { ... }
}
```
### サービス
```Java:OrderService
@Service
public class OrdersService extends BaseService {
    /**  */
    public ResponseEntity<?> get(String orderType) {
        ResponseEntity<?> entity = null;

        // 個別処理呼び出し
        entity = this.callProcess("orders.get", orderType, orderNo);

        // 個別処理が行われなかった場合
        if(entity == null) {
            // ...標準処理...
        }
        
        return entity;
    }
}
```

# チラシの裏
前職での記憶その１。
かつての職場は文系も歓迎、業務内容も既存システムの保守・改善が多く、こういった基盤となるような処理を作れる人が少なかった（利用例の各Executorは既存のコピー実装で作れる、というくらい）。
よって、当時システム開発部でもなかった自分がこのあたりの処理を実装したので、その供養です。