#java #design-patterns
#java #дизайн-шаблоны
Вопрос:
У меня есть один интерфейс с несколькими методами:
interface IExample {
methodA();
methodB();
methodC();
...
methodN();
}
У меня также есть несколько реализаций этого интерфейса (например, класс A, класс B …). У меня также есть HashMap, куда я помещаю эти реализации на основе определенного ключа:
commands = new HashMap<String, IExample>();
commands.put("key1", new A());
.
.
commands.put("keyN", new N());
Я использую шаблон разработки стратегии для извлечения каждой реализации при возникновении какого-либо события:
Event event = ...
IExample example = UtilClass.commands.get(event.getKey());
и теперь я могу вызывать методы для конкретной реализации:
example.methodA();
...
Проблема в том, что в зависимости от события порядок вызова метода разный. Итак, для ключа 1 порядок вызова равен:
example.methodC();
example.methodA();
...
но для другого ключа, скажем, key2, порядок вызова метода:
example.methodA()
example.methodC()
...
Какой шаблон проектирования или подход я могу использовать, чтобы решить эту проблему простым и понятным способом? Не использовать что-то подобное:
if (example instance of A) { call order for A... }
if (example instance of B) { call order for B... }
Комментарии:
1. Вы могли бы написать метод, который вызывает другие методы в некотором порядке, и переопределить его там, где это необходимо, чтобы вызывать их в другом порядке. Это обычная альтернатива
if ( instanceof )
коду.
Ответ №1:
Вы просто добавляете другой метод в свой IExample
интерфейс:
interface IExample {
methodA();
methodB();
methodC();
...
methodN();
execute();
}
class A implements IExample {
//...
execute() {
methodA();
methodC();
}
}
...
commands.get("key1").execute();
В случае, если IExample
интерфейс не удалось изменить или дублируется много порядков, вы можете переместить execute()
метод в другой интерфейс IExecutor
:
interface IExecutor {
execute();
}
class Executor1 implements IExecutor {
private final IExample example;
public Executor1(IExample example) { this.example = example; }
execute() {
example.methodA();
example.methodC();
}
}
и управлять хэш-картой IExecutor
вместо IExample
:
commands = new HashMap<String, IExecutor>();
commands.put("key1", new Executor1(new ExampleA()));
commands.put("key2", new Executor1(new ExampleB()));
...
commands.get("key1").execute();
Ответ №2:
Я бы сделал что-то вроде этого: создайте интерфейс IExecuteOrder
с помощью метода, который говорит: executeOrder(IExample example);
Затем реализуйте этот executeOrder
метод в разных классах в соответствии с вашим порядком выполнения. Например.
class ExecuteOrder1 implements IExecuteOrder{
public executeOrder(IExample example){
example.methodA();
example.methodC();
example.methodB();
}
}
Затем поместите эту реализацию в подобную карту.
Map<String, IExecuteOrder> map = new HashMap<>();
map.put("key1", new ExecuteOrder1());
map.put("key2", new ExecuteOrder2());
...
map.put("keyn", new ExecuteOrderN());
Наконец, вы вызовете свой метод:
map.get("key1").executeOrder(example);
Ответ №3:
Я бы просто объявил другой метод в IExample
интерфейсе:
interface IExample {
methodA();
methodB();
methodC();
// ...
methodN();
runInOrder();
}
Каждый класс должен был бы реализовать этот runInOrder
метод, который просто вызывал methodX
бы методы в требуемом порядке для этого внедрения.
Т.е. класс A
(который соответствует "key1"
) будет реализован runInOrder
следующим образом:
@Override
public void runInOrder() {
this.methodC();
this.methodA();
}
И т.д. Тогда вы могли бы сделать:
Event event = ...
IExample example = UtilClass.commands.get(event.getKey());
example.runInOrder();