Цепочка ответственности гораздо более гибкая, чем описание случая. Важно отметить, что CoR может:
обрабатывать запросы без жесткой связи обработчика и приоритета или сопоставления запроса с обработчиком.
Это означает, что клиенты не знают о каких-либо последующих обработчиках или даже о существовании цепочки.
Количество и тип объектов-обработчиков заранее неизвестны, их можно настроить динамически.
Это означает, что новые обработчики могут быть добавлены во время выполнения, а существующие обработчики могут быть переупорядочены.
Более простой ответ заключается в том, что операторы case представляют собой процедурную конструкцию и поэтому обычно не используются в объектно-ориентированное программирование, такое как шаблоны проектирования Gang of Four.
Онлайн-примеры могут иметь тенденцию к настройке CoR в клиенте для простоты; но на практике это противоречит цели шаблона, поэтому CoR будет настроен в другом месте. Примеры игрушек просто предназначены для того, чтобы показать, как выглядит цепочка и как она работает после инстанцирования; но где он создается, является ключом к мотивации выбора CoR.
Пример: клиент зависит от службы для обработки строкового значения.
API службы тривиален.
interface StringHandler {
void handle(String arg);
}
Клиент может быть бесконечно сложным, но в какой-то момент он вызывает службу.
class Client {
private final StringHandler argHandler;
Client(StringHandler argHandler) {
this.argHandler = argHandler;
}
void method(String arg) {
argHandler.handle(arg);
// more business logic...
}
}
Мы решили реализовать услугу как цепочку ответственности.
class ChainedHandler implements StringHandler {
private final String handledString;
private ChainedHandler next;
ChainedHandler(String handledString) {
this.handledString = handledString;
}
Optional<ChainedHandler> next() {
return Optional.ofNullable(next);
}
ChainedHandler next(ChainedHandler handler) {
ChainedHandler subsequent = next;
next = handler;
if (handler != null && subsequent != null)
handler.next(subsequent);
return this;
}
@Override
public void handle(String arg) {
if (arg.equalsIgnoreCase(handledString)) {
System.out.println("Handled: " + arg);
} else {
next().ifPresentOrElse(
handler -> handler.handle(arg),
() -> System.out.println("No handler for: " + arg));
}
}
}
Итак, мы создаем цепочку, подключаем ее к клиенту и выполняем несколько сценариев, изменяя цепочку.
public static void main(String... commandLineArgs) {
List<String> args = commandLineArgs.length > 0
? Arrays.asList(commandLineArgs)
: List.of("foo", "bar", "baz", "qux");
ChainedHandler chain = new ChainedHandler("foo")
.next(new ChainedHandler("bar")
.next(new ChainedHandler("baz")));
Client client = new Client(chain);
args.forEach(client::method);
System.out.println();
chain.next(new ChainedHandler("qux"));
args.forEach(client::method);
System.out.println();
chain.next(null);
args.forEach(client::method);
}
Обратите внимание, что Client
не знает о существовании цепочки. Кроме того, обратите внимание, что цепочка изменяется без редактирования кода. Это разделение, на которое ссылается GoF. Оператор case или блок if/else не обеспечивают такой же гибкости.
person
jaco0646
schedule
10.12.2015