Использование перечисления для реализации мультитонов в JavaJAVA

Программисты JAVA общаются здесь
Ответить
Anonymous
 Использование перечисления для реализации мультитонов в Java

Сообщение Anonymous »

Мне хотелось бы иметь ограниченный фиксированный каталог экземпляров определенного сложного интерфейса. Стандартный многотонный шаблон имеет некоторые приятные особенности, такие как ленивое создание экземпляров. Однако он опирается на такой ключ, как String, который кажется весьма подверженным ошибкам и хрупким.

Мне нужен шаблон, использующий перечисление. Они обладают множеством замечательных функций и надежны. Я пытался найти для этого стандартный шаблон проектирования, но ничего не получилось. Поэтому я придумал свой собственный, но он мне не очень нравится.

Я использую следующий шаблон (интерфейс здесь сильно упрощен чтобы сделать его читабельным):

Код: Выделить всё

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
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «JAVA»