LoginSignup
4
5

More than 5 years have passed since last update.

Javaでコーディング規約を実装で強制する方法

Last updated at Posted at 2017-03-21

主旨

キャッチーというか、釣り的なタイトルですみませんm(_ _;)m
要はTemplate Methodパターンの実用的な利用方法を説明させてもらいます。
コーディング規約を開発メンバー全員へ浸透させるのは中々難しいものです。時間がなくてコードレビューがおざなりになる、スキルレベルが違う等々、うまくいかない事が多いかなと。
そこで、複数のビジネスロジックを数人で分担して作成する場合、コーディング規約を実装で強制的に守ってもらう基礎となるクラスについて考えてみます。

環境

  • Java:JDK1.5以降

方法

実装するべきメソッド名と引数・戻り値を強制する「必ずこのクラスを継承すること」という唯一のルールのみで、各ビジネスロジッククラスのメソッド名とその役割を強制させる。 要はTemplate Methodパターン。

クラス構成

クラスの構成は以下の通り。
DTOクラス:FooInfoDto.java , BarInfoDto.java
ビジネスロジック親クラス:Proces.java
ビジネスロジッククラス(実装分担部分):ProcesHoge01.java , ProcesHoge02.java
メインクラス(ビジネスロジック呼出し部分):Main.java

1.INPUTとOUTPUTのDTOクラスを用意

処理前の値を保持するクラス(INPUT)のDTO「FooInfoDto」と、
処理後の値を保持するクラス(OUTPUT)のDTO「BarInfoDto 」を作成します。
同じフィールドなので、INPUTもOUTPUTも同じDTOでもいいのですが、処理前と処理後、それぞれどちらに値が保持されるかというのを明確に分けて置いた方が保守性がいい、という理由から冗長ですが分けています。

FooInfoDto.java
package dto;

public class FooInfoDto {

  private Integer id = null;

  private String value = null;

  public Integer getId() {
    return id;
  }

  public void setId(Integer id) {
    this.id = id;
  }

  public String getValue() {
    return value;
  }

  public void setValue(String value) {
    this.value = value;
  }

}
BarInfoDto.java
package dto;

public class BarInfoDto {

  private Integer id = null;

  private String value = null;

  public Integer getId() {
    return id;
  }

  public void setId(Integer id) {
    this.id = id;
  }

  public String getValue() {
    return value;
  }

  public void setValue(String value) {
    this.value = value;
  }

}

2.実装を強制するための親クラスを作成

「各ビジネスロジックは、この親クラスを継承して実装すること」というルールのみで、メソッド名とその役割を強制できるので「どんなクラスで、なんの処理をやっているのか?」という事がわかり易くなります。
インターフェースではなく抽象クラスするのは、一部の処理部分のみ各ビジネスロジックで実装させるためで、共通部分はこの親クラスに集約するためです。

Proces.java
package businesslogic;

import java.util.List;
import dto.BarInfoDto;
import dto.FooInfoDto;

public abstract class Proces {

  protected abstract String getProcesName();

  protected abstract void proces(List<FooInfoDto> input , List<BarInfoDto> output);

  public void execute(List<FooInfoDto> in, List<BarInfoDto> out) {

    System.out.println( getProcesName() + "の処理開始。" );

    proces(in, out);

    System.out.println( getProcesName() + "の処理終了。" );

  }

}

「getProcesNameメソッド」は、『どんな処理をするクラスかを示すためにわかり易い名前を返す』役割を与えます。修飾子を「protected」とすることで、パッケージ外のクラスからは呼出しできないようにしておきます。

「procesメソッド」は、『ビジネスロジックの実際の処理内容を実装するため』の抽象メソッド。こちらも同じく、修飾子を「protected」とすることで、パッケージ外のクラスからは呼出しできないようにしておきます。

「executeメソッド」は、利用側、つまりメインクラス(businesslogicパッケージの外のクラス)から呼出し可能な唯一のメソッド。ここでフック処理や、処理順番などを強制できます。

3.分担で実装するビジネスロジックの様子

実際にメンバーに実装してもらう部分。

ProcesHoge01.java
package businesslogic;

import java.util.List;
import dto.BarInfoDto;
import dto.FooInfoDto;

public class ProcesHoge01 extends Proces {

  @Override
  protected String getProcesName() {
    return "Hoge01処理";
  }

  @Override
  protected void proces(List<FooInfoDto> input, List<BarInfoDto> output) {

    // 実際のHoge処理内容
    int index = 0;
    for( FooInfoDto dto : input ) {

      Integer tmpId = dto.getId()*10;
      output.get(index).setId(tmpId);

      String tmpValue = dto.getValue()+"_Hoge01";
      output.get(index).setValue(tmpValue);

      index++;
    }
  }
}
ProcesHoge02.java
package businesslogic;

import java.util.List;
import dto.BarInfoDto;
import dto.FooInfoDto;

public class ProcesHoge02 extends Proces {

  @Override
  protected String getProcesName() {
    return "Hoge02処理";
  }

  @Override
  protected void proces(List<FooInfoDto> input, List<BarInfoDto> output) {

    // 実際のHoge処理内容
    int index = 0;
    for( FooInfoDto dto : input ) {

      Integer tmpId = dto.getId() + output.get(index).getId();
      output.get(index).setId(tmpId);

      String tmpValue = dto.getValue()+"_Hoge02";
      output.get(index).setValue(tmpValue);

      index++;
    }
  }
}

4.ビジネスロジックを呼び出すクラス

実際は、コントローラークラスにあたる部分です。ここではわかり易く単なるmainメソッドで実行するだけのクラスとして実装しています。パッケージもデフォルトのままにしてしまっていますが、ビジネスロジッククラス群のパッケージとは別にしてもらえればいい感じです。

Main.java
import java.util.ArrayList;
import java.util.List;
import businesslogic.ProcesHoge01;
import businesslogic.ProcesHoge02;
import dto.BarInfoDto;
import dto.FooInfoDto;

public class Main {

  public static void main(String[] args) {

    //処理結果を保管するDTOリスト
    List<BarInfoDto> out = new ArrayList<BarInfoDto>();

    //処理対象となる入力DTOリストを用意
    List<FooInfoDto> in = new ArrayList<FooInfoDto>();
    for(int i=1 ; i<4 ; i++){
      FooInfoDto dto = new FooInfoDto();
      dto.setId(i);
      dto.setValue(i+"番目の値");

      //処理対象となる入力DTOリストにセット
      in.add(dto);

      //処理結果を保管するDTOリストには空のDTOオブジェクトをセット
      out.add(new BarInfoDto());

    }

    new ProcesHoge01().execute(in, out);
    //結果表示
    for(BarInfoDto dto : out) {
      System.out.println( "-------------------------------" );
      System.out.println( "処理後のID    > " + dto.getId() );
      System.out.println( "処理後のValue > " + dto.getValue() );
    }

    new ProcesHoge02().execute(in, out);
    //結果表示
    for(BarInfoDto dto : out) {
      System.out.println( "-------------------------------" );
      System.out.println( "処理後のID    > " + dto.getId() );
      System.out.println( "処理後のValue > " + dto.getValue() );
    }
  }
}

以上です。

備考

如何だったでしょうか? 
ご意見、アドバイスなど頂けたら幸いです。m(_ _)m

メインクラスをFacadeパターンのFacadeクラスにして、さらに可読性を上げてもいいと思います。

4
5
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
4
5