コンストラクタのデザインパターン – java


テレスコーピング・コンストラクタ パターン

/*
*
* テレスコーピング・コンストラクタ パターン
* 引数違いで複数の同名コンストラクタを設定
*
*/
public class TelescopingConstructor {

	// -- 一意番号(必須)
	private int Id ;
	// --名前
	private String Name;
	// --年齢
	private int Age;
	// --有効フラグ(必須 : 初期値[false])
	private Boolean EnableFlg;

	public TelescopingConstructor(int _id) {
		this(_id,"");
	}

	public TelescopingConstructor(int _id,String _name) {
		this(_id,_name,0);
	}

	public TelescopingConstructor(int _id,String _name,int _Age) {
		this(_id,_name,_Age,false);
	}

	public TelescopingConstructor(int _id,String _name,int _Age,Boolean _Enable) {
		this.Id = _id;
		this.Name = _name;
		this.Age = _Age;
		this.EnableFlg = _Enable;

		System.out.println("[Id : " + this.Id + "]" +
				           " [Name : " + this.Name + "]" +
				           " [Age : " + this.Age + "]" +
				           " [EnableFlg : " + this.EnableFlg + "]");
	}

}

クライアント側での呼び出し

// -- テレスコーピング・コンストラクタ 呼出
TelescopingConstructor _TelescopingConstructor = new TelescopingConstructor(1);

伝統的に使用されているコンストラクタパターン。
プログラマのほとんどがまずこのコンストラクタから習得するのではないでしょうか。
引数違いの同名コンストラクタを複数宣言することにより、呼び出し側で必要なパタメータを取捨選択できます。
デメリットとしては、詳細なコメントが記載されていなければ、呼び出し側でどのコンストラクタを使用すればいいか分からなくなってしまうことです。
引数の数が多く、また型も似通ったものが多いなら、可読性が悪くなってしまいます。

JavaBeans・コンストラクタ パターン

/*
*
* JavaBeans・コンストラクタ パターン
* インスタンス化後、各setterで変数値を設定
*
*/
public class JavaBeansConstructor {

	// -- 一意番号(必須)
	private int Id ;
	// --名前
	private String Name;
	// --年齢
	private int Age;
	// --有効フラグ(必須 : 初期値[false])
	private Boolean EnableFlg = false;

	public void setId(int _id) {this.Id = _id;}
	public void setName(String _name) {this.Name = _name;}
	public void setAge(int _age) {this.Age = _age;}
	public void setEnableFlg(Boolean _Enable) {this.EnableFlg = _Enable;}

	public void PrintOut() {

		System.out.println("[Id : " + this.Id + "]" +
		                   " [Name : " + this.Name + "]" +
		                   " [Age : " + this.Age + "]" +
		                   " [EnableFlg : " + this.EnableFlg + "]");

	}
}

クライアント側での呼び出し

// -- JavaBeans・コンストラクタ 呼出
JavaBeansConstructor _JavaBeansConstructor = new JavaBeansConstructor();
// -- _JavaBeansConstructor.setId(ID);
_JavaBeansConstructor.setName(NAME);
_JavaBeansConstructor.setAge(AGE);
_JavaBeansConstructor.setEnableFlg(ENABLEFLG);
_JavaBeansConstructor.PrintOut();

コンストラクタではパラメータを受け取らず、各メンバに対してセッターを準備してあげるパターンです。
多少コードが長くなってしまいますが、テレスコーピング・コンストラクタとは異なり可読性に優れたコンストラクタになります。
デメリットとしては、生成過程の途中において不整合な状態にあるかもしれないということです。
パラメータを1つも必要とせずインスタンス化できてしまうので、メンバの値のセットは呼び出し側に依存し、場合によってはクラス内のメンバが不整合な値のまま処理が実行してしまいます。
上記のクライアント側での呼び出しは必須項目のIDがセットされないまま処理が実行されてしまっています。

Builder・コンストラクタ パターン

/*
*
* Builder・コンストラクタ パターン
* テレスコーピングパターンとJavaBeansパターンを組み合わせたコンストラクタ
*
*/
public class BuilderConstructor {

	// -- 一意番号(必須)
	private int Id ;
	// --名前
	private String Name;
	// --年齢
	private int Age;
	// --有効フラグ(必須)
	private Boolean EnableFlg;

	// -- ビルダークラス
	public static class Builder{

		private int id ;
		private String name;
		private int age;
		private Boolean enableflg;

		// -- 必須値はコンストラクタで受取
		public Builder(int _id,Boolean _enable) {
			this.id = _id;
			this.enableflg = _enable;
		}

		// -- 任意値はSetterで受取
		public Builder setName(String _name) {this.name = _name; return this;}
		public Builder setAge(int _age) {this.age = _age; return this;}

		// -- 設定された変数値でBuilderConstructorインスタンスを生成
		public BuilderConstructor Build() {
			return new BuilderConstructor(this);
		}

	}

	// -- ビルダークラスが保持している変数値でインスタンスを生成
	private BuilderConstructor(Builder _Builder) {
		this.Id = _Builder.id;
		this.Name = _Builder.name;
		this.Age = _Builder.age;
		this.EnableFlg = _Builder.enableflg;

		System.out.println("[Id : " + this.Id + "]" +
		                   " [Name : " + this.Name + "]" +
		                   " [Age : " + this.Age + "]" +
		                   " [EnableFlg : " + this.EnableFlg + "]");
	}

}

クライアント側での呼び出し

// -- Builder・コンストラクタ 呼出
BuilderConstructor _BuilderConstructor = new BuilderConstructor.Builder(ID,ENABLEFLG).setAge(AGE).setName(NAME).Build();

テレスコーピングパターンとJavaBeansパターンを組み合わせたようなコンストラクタパターンです。
必須パラメータをコンストラクタで受け取り、任意パラメータをセッターで受け取ります。
また、インスタンス化するためにBuild()メソッドを呼ぶ必要があるので、Buildメソッド内でパラメータの整合性チェックをすれば不整合な状態で処理が実行されることもなくなります。
デメリットとしては、多少手間がかかることと、コードが長くなってしまうことです。
ですが、当パターンならクライアント側からの呼び出しは容易になり、不整合な状態もなくなります。

まとめ

一口にコンストラクタといっても様々なデザインパターンがあり、それぞれにメリットとデメリットがあります。
理想は用途にあったパターンを使用することではないでしょうか。
ですが、実際には様々なコンストラクタパターンで記述されているシステムは読み手側の技術も必要になってきます。
なので、どのコンストラクタを使うべきとは明示できませんが、参考になればと思います。

ご清聴ありがとうございました。

シェアする

  • このエントリーをはてなブックマークに追加

フォローする