【Java】Enumを使って変更に強いコードを書こう！

<h2>概要</h2>
仕事でコード値の判定が色んなところに散らばってしまった後に、コード値の定義を変更しなければいけなくなった状況が起こりました。
Enumで定義していれば変更箇所はEnum定義だけでよかったなぁ～と思い、自戒の意味を込めて執筆致しました。

<h2>状況</h2>
<ul>
<li>「なんちゃら種別」のような種別コード値と名称が複数定義されている</li>
<li>その定義の中に、「3：その他」が最後に定義されていた。</li>
<li>新たに追加されることになった種別コードは「3」を使いたい。</li>
<li>そのため、「その他」は今後さらにコード値が追加されることを考慮して、
「99：その他」にしたい。</li>
</ul>

<h2>実装</h2>
<h3>問題のあるコード</h3>
<strong>SalesOrderMain.java</strong>
アプリケーションのエントリーポイント（実行開始メソッド）

```SalesOrderMain.java
package main.enum_case;

public class SalesOrderMain {
	public static void main(String...strings) {
		SalesOrder otherOrder = new SalesOrder("販売停止商品", 0, 3);

		// OTHER=3をハードコーディングで判定する場合
		// ⇒ ロジックは通るが、コード値を修正したらif文を修正する必要がある
		if(3 == otherOrder.saleKindCode()) {
			System.out.println("コード値3：販売停止商品です。[ハードコーディング]");
		}

		// OTHERをEnumで判定していた場合
		// ⇒ コードを変更することなく動作する
		if(SalesKind.OTHER.code() == otherOrder.saleKindCode()) {
			System.out.println("コード値" + SalesKind.OTHER.code()+ "：販売停止商品です。[Enum定義]");
		}
	}
}
```

<blockquote>
<strong>実行結果</strong><br>
一応ハードコーティングとEnum定義での両方でロジックが通っています。
<pre class="lang:xhtml decode:true " >コード値3：販売停止商品です。[ハードコーディング]
コード値3：販売停止商品です。[Enum定義]</pre>

<code>if(3 == otherOrder.saleKindCode()) </code><br>
しかしここが<span class="rmarker">ハードコーディングになっているので、コード値の修正に対応していません。</span>
</blockquote>


<strong>SalesOrder.java</strong>
売上種別コードを持つオブジェクト

```SalesOrder.java
package main.enum_case;

public class SalesOrder {
	private String _name;
	private Integer _amount;
	private Integer _salesKindCode;

	SalesOrder(String name, Integer amount, Integer salesKindCode){
		_name = name;
		_amount = amount;
		_salesKindCode = salesKindCode;
	}

	public Integer saleKindCode() {
		return _salesKindCode;
	}
}
```

<strong>SalesKind.java</strong>
販売種別=3(その他)が定義されている状態

```SalesKind.java
package main.enum_case;

public enum SalesKind {
	A(1, "A"),
	B(2, "B"),
	OTHER(3, "OTHER");	

	private Integer _code;
	private String _name;

	private SalesKind(Integer code, String name) {
		_code = code;
		_name = name;
	}

	public Integer code() {
		return _code;
	}

	// Enumで定義されているnameメソッドを重複すため、nameのプロパティはofNameとする。
	public String ofName() {
		return _name;
	}
}
```

　
<h3>Enum定義で解消したコード</h3>
<strong>SalesOrderMain.java</strong>
アプリケーションのエントリーポイント（実行開始メソッド）
SalesOrderのインスタンス生成時の売上種別を99に変更しています。 

```SalesOrderMain.java
package main.enum_case;

public class SalesOrderMain {
	public static void main(String...strings) {
		SalesOrder otherOrder = new SalesOrder("販売停止商品", 0, 99); // 99に変更

		// OTHER=3をハードコーディングで判定する場合
		// ⇒ ロジックは通るが、コード値を修正したらif文を修正する必要がある
		if(3 == otherOrder.saleKindCode()) {
			System.out.println("コード値3：販売停止商品です。[ハードコーディング]");
		}

		// OTHERをEnumで判定していた場合
		// ⇒ コードを変更することなく動作する
		if(SalesKind.OTHER.code() == otherOrder.saleKindCode()) {
			System.out.println("コード値" + SalesKind.OTHER.code()+ "：販売停止商品です。[Enum定義]");
		}
	}
}
```

<blockquote>　
<strong>実行結果</strong>
Enum定義で判定していたロジックのみ通っています。
<pre class="lang:xhtml decode:true " >コード値99：販売停止商品です。[Enum定義]
</pre> 

<code>if(3 == otherOrder.saleKindCode())</code><br>
ここは<span class="rmarker">ハードコーディングしていたため、修正しなくてはならなくなりました。</span></blockquote>



<strong>SalesOrder.java</strong>
売上種別コードを持つオブジェクト
修正箇所は無いため割愛

<strong>SalesKind.java</strong>
販売種別=99(その他)に定義し直した状態
 
```SalesKind.java
package main.enum_case;

public enum SalesKind {
	A(1, "A"),
	B(2, "B"),
	C(3, "C"),
//	OTHER(3, "OTHER");	// 元々は3だったが、3が追加されたために99に変更することになった
	OTHER(99, "OTHER");

	private Integer _code;
	private String _name;

	private SalesKind(Integer code, String name) {
		_code = code;
		_name = name;
	}

	public Integer code() {
		return _code;
	}

	// Enumで定義されているnameメソッドを重複すため、nameのプロパティはofNameとする。
	public String ofName() {
		return _name;
	}
}
```


<h2>まとめ</h2>
<ul>
<li>コード値の判定ロジックはEnum定義などを利用し、変更に強い構造にしておくこと。</li>
</ul>