Мне нужен шаблон, использующий перечисление. Они обладают множеством замечательных функций и надежны. Я пытался найти для этого стандартный шаблон проектирования, но ничего не получилось. Поэтому я придумал свой собственный, но он мне не очень нравится.
Я использую следующий шаблон (интерфейс здесь сильно упрощен чтобы сделать его читабельным):
Код: Выделить всё
interface Complex {
void method();
}
enum ComplexItem implements Complex {
ITEM1 {
protected Complex makeInstance() { return new Complex() { ... }
},
ITEM2 {
protected Complex makeInstance() { return new Complex() { ... }
};
private Complex instance = null;
private Complex getInstance() {
if (instance == null) {
instance = makeInstance();
}
return instance;
}
protected void makeInstance() {
}
void method {
getInstance().method();
}
}
- перечисление реализует интерфейс, который делает его использование довольно естественным: ComplexItem.ITEM1.method();
- Отложенное создание экземпляров: если конструкция требует больших затрат (мой вариант использования предполагает чтение файлов), она происходит только в том случае, если она требуется.
У него есть еще один существенный недостаток. В моем случае использования я бы хотел, чтобы интерфейс расширял Comparable. К сожалению, тогда это противоречит реализации перечисления Comparable и делает код некомпилируемым.
Одной альтернативой, которую я рассматривал, было наличие стандартного перечисления, а затем отдельного класса, который сопоставляет перечисление с реализация интерфейса (с использованием стандартного многотонного шаблона). Это работает, но перечисление больше не реализует интерфейс, который, как мне кажется, не является естественным отражением намерения. Он также отделяет реализацию интерфейса от элементов перечисления, что кажется плохой инкапсуляцией.
Другая альтернатива — заставить конструктор перечисления реализовать интерфейс (т.е. в шаблоне выше устраните необходимость в методе makeInstance). Хотя это работает, оно лишает преимущества запуска конструкторов только при необходимости). Это также не решает проблему с расширением Comparable.
Итак, мой вопрос: может ли кто-нибудь придумать более элегантный способ сделать это?
В ответ на комментарии я попытаюсь указать конкретную проблему, которую пытаюсь решить, сначала в общих чертах, а затем на примере.
- Существует фиксированный набор объектов, реализующих данный интерфейс.
- Объекты не имеют состояния: они используются только для инкапсуляции поведения.
- При каждом выполнении кода будет использоваться только подмножество объектов (в зависимости от ввода пользователя).
- Создание этих объектов обходится дорого: его следует делать только один раз и только при необходимости
- У объектов много общего.
Теперь пример. Система рассчитывает несколько разных налогов в наборе регионов, каждый из которых имеет свой алгоритм расчета налогов. Ожидается, что набор регионов никогда не изменится, но региональные алгоритмы будут регулярно меняться. Конкретные региональные тарифы необходимо загружать во время выполнения через удаленную службу, что является медленным и дорогостоящим процессом. При каждом вызове системы ей будет предоставлен другой набор регионов для расчета, поэтому она должна загружать только ставки запрошенных регионов.
Итак:
Код: Выделить всё
interface TaxCalculation {
float calculateSalesTax(SaleData data);
float calculateLandTax(LandData data);
....
}
enum TaxRegion implements TaxCalculation {
NORTH, NORTH_EAST, SOUTH, EAST, WEST, CENTRAL .... ;
private loadRegionalDataFromRemoteServer() { .... }
}
Подробнее здесь: https://stackoverflow.com/questions/259 ... ns-in-java
Мобильная версия