仕事で問題にぶつかり、列挙型がどのように成長し、ビジネスロジックを格納しているかを確認しました。彼らが成長するにつれて、コンストラクタは大きく成長しました。ある時点で、10番目のブール型パラメーター(およびブール値以外のさまざまなパラメーターが既に含まれている)をコンストラクターに置く代わりに、すべての初期化を追加のパラメーターで展開すると、新しいパラメーターを作成しますが、実際にはそうではありませんused-コードを読みやすくするための構造。
ここに例があるので、代わりに:
public enum A {
A1(true, true, false),
A2(true, false, true),
A3(false, false, false);
private A(boolean firstParam, boolean secondParam, boolean thirdParam){
... usual constructor ...
}
... getters
だから代わりに私は次のことをしました:
public enum A {
A1,
A2,
A3;
... no need for special constructor
public boolean isFirstParam(){
switch(this){
case A1:
case A2:
return true;
default:
return false;
}
}
public boolean isSecondParam(){
switch(this){
case A1:
return true;
default:
return false;
}
}
public boolean isThirdParam(){
switch(this){
case A2:
return true;
default:
return false;
}
}
これまでのところ、それを使用した人は誰でも気に入っています。しかし、それを知らない同僚の中には悪い反応を示した人もいました。
私の質問は、私がそれを使用すべきではない本当の理由はありますか?複雑な列挙型があると、より保守しやすくなります。特別な場所ではなく、列挙型を切り替えるだけで、特別なことは何も使用しなかったと思います。私は正しいですか?
他の選択肢は、インスタンスごとにメソッドをオーバーライドすることです:
public enum A {
A1{
@Override public boolean isFirstParam(){ return true; }
@Override public boolean isSecondParam(){ return true; }
@Override public boolean isThirdParam(){ return false; }
},
A2{
@Override public boolean isFirstParam(){ return true; }
@Override public boolean isSecondParam(){ return false; }
@Override public boolean isThirdParam(){ return false; }
},
A3{
@Override public boolean isFirstParam(){ return false; }
@Override public boolean isSecondParam(){ return false; }
@Override public boolean isThirdParam(){ return false; }
};
public abstract boolean isFirstParam();
public abstract boolean isSecondParam();
public abstract boolean isThirdParam();
}
https://docs.Oracle.com/javase/8/docs/technotes/guides/language/enums.html には次のように書かれています。
列挙型定数に動作を追加するという考えは、さらに一歩進めることができます。一部のメソッドでは、各列挙定数に異なる動作を与えることができます。列挙定数をオンにしてこれを行う1つの方法。以下は、定数が4つの基本的な算術演算を表し、evalメソッドが演算を実行する列挙型の例です。
public enum Operation { PLUS, MINUS, TIMES, DIVIDE; // Do arithmetic op represented by this constant double eval(double x, double y){ switch(this) { case PLUS: return x + y; case MINUS: return x - y; case TIMES: return x * y; case DIVIDE: return x / y; } throw new AssertionError("Unknown op: " + this); } }
これは正常に機能しますが、throwステートメントがないとコンパイルできません。さらに悪いことに、新しい定数をOperationに追加するたびに、switchステートメントに新しいケースを追加することを忘れないでください。忘れた場合、evalメソッドは失敗し、前述のthrowステートメントを実行します
これらの問題を回避するいくつかのメソッドに対して、各列挙型定数に異なる動作を与える別の方法があります。 enum型でメソッドの抽象を宣言し、各定数の具象メソッドでオーバーライドできます。このような方法は、定数固有の方法として知られています。このテクニックを使用してやり直した前の例を次に示します。
public enum Operation { PLUS { double eval(double x, double y) { return x + y; } }, MINUS { double eval(double x, double y) { return x - y; } }, TIMES { double eval(double x, double y) { return x * y; } }, DIVIDE { double eval(double x, double y) { return x / y; } }; // Do arithmetic op represented by this constant abstract double eval(double x, double y); }
個人的には、例外をスローしてすべての可能性を明示的に処理することを気にしません。exceptスイッチが列挙自体に配置される場合。 IDEは、すべてのケースを処理しない場合に警告を表示します(コンパイルできないようにエラーに変換するように構成することもできます)。プロジェクトの警告を表示しない場合私がやろうとしているのは、どのファイルのswitchステートメントを更新する必要があるかすぐにわかるでしょう。