私が扱っている問題について説明しましょう。実稼働コードで使用するカスタム(jar)APIがあります。このAPIには、次のようなENUMが含まれています。
_public enum Cars {
AUDI("BERLIN", "FRANKFURT", "HAMBURG", "MUNICH")
VW("BERLIN", "FRANKFURT"),
MERCEDES("HAMBURG", "MUNICH")
private final String[] cityNames;
Cars(String... cityNames) {
this.cityNames = cityNames;
}
public isCityNameAvailable(String cityName) {
for (String city : cityNames) {
if (cityName.equals(city)) {
return true;
}
}
return false;
}
}
_
このシンプルなENUMには、利用可能な自動車と都市が含まれています。これまでのところ、本番コードロジックは次のように機能します。
Cars.values()
からすべての車を1つずつ調べます。新しい要件は、利用可能な車に新しい制約ディーラーを追加する必要があることを示しています。つまり、都市に加えて、車が利用できる(購入できる)ディーラーに基づいてフィルターを適用する必要があります。
ただし、ディーラー制約は1台以上の車に適用できます。たとえば、AUDIのみが都市名とディーラーに基づいてフィルタリングされると想定されています。他のすべての車は、ディーラーが利用可能かどうかに関係なく、(都市に基づいて)常に利用可能です。
単純な解決策があったでしょう。 enumを次のように更新します。
_public enum Cars {
AUDI("COOL AUTOS", "BERLIN", "FRANKFURT", "HAMBURG", "MUNICH")
VW("ALL", "BERLIN", "FRANKFURT"),
MERCEDES("ALL", "HAMBURG", "MUNICH")
private String dealerName;
private final String[] cityNames;
Cars(String dealerName, String... cityNames) {
this.dealerName = dealerName;
this.cityNames = cityNames;
}
// rest
}
_
コードフローは次のようになります。
ALL
販売店で入手できます。したがって、ディーラー名は無関係です。もう一つの例:
ALL
販売店で利用できます。問題:
解決策が気に入らない。それは柔軟性がありません、今日フィルターはディストリビューター、都市と車の関係に基づいて構築される必要があります。明日は別のことになるかもしれません。新しい要件に基づいて、ENUMに密結合を追加しました。
質問
ENUMの機能を強化するために使用できるデザインパターンはありますか?私が好きなだけフィルターを追加できますENUM自体にロジックを構築せずに?
機能を強化することは、車、都市、および(新しい)制約の間の関係も意味しますか?
[〜#〜]編集[〜#〜]
!=
_メーカーを明確にしました。ENUM
の一部になるシナリオは、この問題の問題ではありません。これに特定のパターンがあるかどうかはわかりませんが、より柔軟な他の方法でこれを処理するさまざまなアプローチがあります。まず、これは非常に厳しく、もろいようです。確かに言うには、ここでのコンテキストについては十分にわかりませんが、自動車メーカーの名前は、ハードコーディングしたいもののようには見えません。列挙型はハードコーディングで取得できるのと同じくらいハードコードされているため、ここではまったく最適なソリューションではない可能性があります。
とはいえ、列挙型の機能の1つは、switchステートメントで機能することです。したがって、次のようなことを簡単に実行できます(Java 12/13を使用していると仮定):
boolean match = switch(brand) {
case Audi -> distributorName == "COOL AUTOS";
default -> true;
}
この新しいスイッチ構文では、これを 述語 ラムダとして使用できます。
別のオプションは、ディストリビューター名とそれらがサポートするメーカーをキーにしたマップを作成することです。これは、ハードコーディングする代わりに、データベースまたは他のデータソースにその情報を格納するソリューションに役立ちます。
あなたのコメントに基づいて、あなたはより単純なルールエンジンに向かっているように思えます。あなたが与えた要件については、これはかなり簡単です。
基本的な構造は次のようになります。
private Map<Cars, List<Rules>> rules = new HashMap<>();
void addRule(Cars car, Rule rule) {
List<Rules> list = rules.get(car);
if (list == null) {
list = new ArrayList<>();
rules.put(car, list);
}
list.add(rule);
}
boolean canBuy(Cars car, Location location, Distributor distributor) {
for (Rule rule : rules.get(car)) {
if (rule.isRestricted(location, distributor)) return false;
}
return true;
}
Rule
は次のように定義されています:
public interface Rule {
boolean isRestricted(Location location, Distributor distributor);
}
次に、次のようにルールマップを入力できます。
addRule(AUDI, (loc, dist) -> loc == BERLIN && dist == COOLAUTOS);
単純化のためにPerson制約を無視し、ロケーションとディストリビューターも独立したEnumであると想定しています。
繰り返しますが、ここでの列挙型の使用には疑問があります。列挙型は、変更が予期されないものや、コード内の他の変更によってのみ変更されるものに適しています。ブランド、ロケーション、ディストリビューターなどは、特にこのシステムを使用するビジネスが成功した場合、変わる可能性があります。任意のオブジェクトをマップおよび通常のクラスのキーとして使用して、場所やディストリビューターなどを実装できます。ここで概説したこのアプローチは、列挙型に依存していません。