Почти каждая проблема в Информатике может быть решена путем добавления уровня абстракции*, или что-то.
Так представляют неродовой объект, который имеет более высокий уровень что Map
. Без контекста это не собирается выглядеть очень убедительным, но так или иначе:
public final class Items implements java.io.Serializable {
private static final long serialVersionUID = 1L;
private Map<String,String> map;
public Items(Map<String,String> map) {
this.map = New.immutableMap(map);
}
public Map<String,String> getMap() {
return map;
}
@Override public String toString() {
return map.toString();
}
}
public final class New {
public static <K,V> Map<K,V> immutableMap(
Map<? extends K, ? extends V> original
) {
// ... optimise as you wish...
return Collections.unmodifiableMap(
new HashMap<String,String>(original)
);
}
}
static Map<String, String> getItems(HttpSession session) {
Items items = (Items)
session.getAttribute("attributeKey");
return items.getMap();
}
*Except слишком много уровней абстракции.
Проблема в том, что это не помогает в реальных проблемных случаях, которые это когда есть несколько аргументов и неясно, что контролирует «флаг».
Если вы следуете правилу, согласно которому вы должны «избегать двойных отрицаний», тогда подойдут простые одинарные логические значения:
public static void Foo(bool useBaz)
public static void Foo(Ability useBaz)
Тогда Foo (true)
, стихи Foo (Ability.Enabled)
и Foo (false)
, стихи Foo (Ability.Disabled)
действительно довольно очевидны для большинство.
Однако, когда вы нажимаете такой метод, как:
public static void Foo(
bool useBaz,
bool barIsHigh,
bool useFlibble,
bool ignoreCase)
, тогда не имеет значения, используете ли вы логические или общие перечисления, они оба в конечном итоге выглядят так на сайте вызова:
Foo(false,true,false,false);
Foo(Ability.Enabled,Ability.Enabled,Ability.Disabled,Ability.Enabled);
Ни то, ни другое не красиво.
Использование конкретных перечислений для рассматриваемого случая:
enum BarOption { Off, On }
enum BazConsidered { Low, High }
enum FlibbleOption { Off, On }
// for case sensitivity use System.StringComparison
тогда вы получите
Foo(Bar.On,
BazConsidered.Low,
FlibbleOption.On,
StringComparison.IgnoreCase );
или, если все они являются простыми логическими состояниями и, вероятно, останутся таковыми, тогда еще лучше использовать помеченное перечисление.
[Flags]
enum FooOptions
{
None = 0,
UseBaz = 1,
BazConsideredHigh = 2,
UseFlibble = 4,
}
] Тогда у вас будет:
Foo(FooOptions.UseBar | FooOptions.UseFlibble, StringComparison.IgnoreCase);
Соответствующий выбор «активных» флагов, чтобы вы указали только то, что необычно, затем приведет к выделению «необычных» использований.
Что плохого в использовании параметров bool
с осмысленными именами?
public void Foo(bool clickabilityEnabled, bool editabilityEnabled) { ... }
Или, еще лучше, что-то менее подробное:
public void Bar(bool isClickable, bool isEditable, bool isSerializable) { ... }
public void Baz(bool canClick, bool canEdit, bool canSerialize) { ... }
Я бы нашел это гораздо более читаемым чем загружает параметры перечисления
.
Нет, такого перечисления в BCL нет (насколько мне известно). Но нетрудно взять один из тех, что вы постоянно создаете, и сделать его более общим:
public enum Ability
{
Disabled,
Enabled
}
Вставьте его в какую-нибудь библиотеку классов с аналогичными общими вещами и повторно используйте в своих проектах.