
Этот шаблон проектирования относится к категории поведенческих шаблонов проектирования. Основной целью цепочки ответственности является слабая связь, в качестве примера рассмотрим связь между отправителем и получателем, отправитель не знает, кто является получателем, а получатель не знает, кто является отправителем. Это просто означает, что этот шаблон проектирования разделяет отправителя и получателя запроса на основе типа запроса.
Ситуация, в которой разработчики могут использовать шаблон цепочки ответственности?
· Когда разработчик хочет разделить отправителя и получателя запроса
· Несколько объектов, определенных во время выполнения, являются кандидатами для обработки запроса
· Когда разработчик не хочет явно указывать обработчики в коде
· Когда разработчик хочет сделать запрос к одному из нескольких объектов без явного указания получателя.

Как вы можете видеть на приведенной выше диаграмме UML, в этом шаблоне проектирования он использует класс, называемый обработчиком, для разделения отправителя и получателя.
Пример:
Предположим, что авиакомпании требуется программное обеспечение, которое создает план количества топлива, который будет рассчитывать потребность самолета в топливе на основе его летных часов.
Шаг 1: Реализуйте абстрактный класс обработчика.
В классе обработчика создайте ссылочную переменную, которая содержит преемника, и создайте абстрактный метод с именем
«рассчитатьMaxFuelQuantity (FuelQuantityPlan fuelQuantityPlan)».
package ChainOfResponsibilityExample;
public abstract class FuelQuantityHandler {
protected FuelQuantityHandler successor;
public void setSuccessor(FuelQuantityHandler successor) {
this.successor = successor;
}
public abstract float calculateMaxFuelQuantity (FuelQuantityPlan fuelQuantityPlan);
}
Примечание. Кроме того, этот класс можно создать как класс интерфейса, а не реализовать как абстрактный класс. Но в этом примере я реализовал его как абстрактный класс.
Шаг 2: Создайте класс плана количества топлива, объявите переменные экземпляра и реализуйте соответствующие конструкторы, сеттеры и геттеры.
package ChainOfResponsibilityExample;
public class FuelQuantityPlan {
private String flightPath;
private float flyingHours;
private float fuelQuantity;
public void setFuelQuantity(float fuelQuantity) {
this.fuelQuantity = fuelQuantity;
}
public FuelQuantityPlan(String flightPath, float flyingHours) {
this.flightPath = flightPath;
this.flyingHours = flyingHours;
}
public String getFlightPath() {
return flightPath;
}
public float getFlyingHours() {
return flyingHours;
}
public float getFuelQuantity() {
return fuelQuantity;
}
}
Шаг 3: Создайте классы-приемники и сделайте класс-обработчик родительским классом.
Примечание. Здесь показаны только первый и последний классы получателей, чтобы уменьшить сложность и объем статьи.
package ChainOfResponsibilityExample;
public class ShortRange extends FuelQuantityHandler{
@Override
public float calculateMaxFuelQuantity(FuelQuantityPlan fuelQuantityPlan) {
fuelQuantityPlan.setFuelQuantity((float) (fuelQuantityPlan.getFlyingHours() * 0.2));
System.out.println("Short Range Fuel Quantity Added");
if ( fuelQuantityPlan.getFlyingHours() <= 5) {
return fuelQuantityPlan.getFuelQuantity();
} else {
return successor.calculateMaxFuelQuantity(fuelQuantityPlan);
}
}
}
package ChainOfResponsibilityExample;
public class IntercontinentalRange extends FuelQuantityHandler{
@Override
public float calculateMaxFuelQuantity(FuelQuantityPlan fuelQuantityPlan) {
fuelQuantityPlan.setFuelQuantity((float) (fuelQuantityPlan.getFuelQuantity() + (fuelQuantityPlan.getFlyingHours() - 12.5) * 0.8));
System.out.println("Intercontinental Range Fuel Quantity Added");
return fuelQuantityPlan.getFuelQuantity();
}
}
Сначала вычислите соответствующее значение, после этого проверьте, подходит ли это значение для расчета следующего количества топлива. Если оно подходит, текущий экземпляр класса плана количества топлива будет передан в качестве аргумента для метода «calculateMaxFuelQuantity» экземпляра-преемника.
В последнем классе, который подпадает под категорию класса приемника, нам нужно только рассчитать окончательное количество топлива и передать количество топлива.
Шаг 4: Создайте начальный класс, который инициирует шаблон проектирования цепочки ответственности.
Примечание. Это необязательный шаг, разработчик может инициировать цепочку ответственности, используя первый класс получателя.
package ChainOfResponsibilityExample;
public class MinimumFuelQuantity extends FuelQuantityHandler{
@Override
public float calculateMaxFuelQuantity(FuelQuantityPlan fuelQuantityPlan) {
return successor.calculateMaxFuelQuantity(fuelQuantityPlan);
}
}
Шаг 5: Создайте основной метод и посмотрите, как работает шаблон проектирования цепочки ответственности.
package ChainOfResponsibilityExample;
public class Application {
public static void main(String[] args) {
ShortRange shortRange = new ShortRange();
MidRange midRange = new MidRange();
LongRange longRange = new LongRange();
IntercontinentalRange intercontinentalRange = new IntercontinentalRange();
MinimumFuelQuantity minimumFuelQuantity = new MinimumFuelQuantity();
minimumFuelQuantity.setSuccessor(shortRange);
shortRange.setSuccessor(midRange);
midRange.setSuccessor(longRange);
longRange.setSuccessor(intercontinentalRange);
FuelQuantityPlan fuelQuantityPlan = new FuelQuantityPlan("AB1", 2.0f);
System.out.println(minimumFuelQuantity.calculateMaxFuelQuantity(fuelQuantityPlan));
FuelQuantityPlan fuelQuantityPlan1 = new FuelQuantityPlan("AB2", 6.0f);
System.out.println(minimumFuelQuantity.calculateMaxFuelQuantity(fuelQuantityPlan1));
FuelQuantityPlan fuelQuantityPlan2 = new FuelQuantityPlan("AB3", 8.0f);
System.out.println(minimumFuelQuantity.calculateMaxFuelQuantity(fuelQuantityPlan2));
FuelQuantityPlan fuelQuantityPlan3 = new FuelQuantityPlan("AB4", 14.0f);
System.out.println(minimumFuelQuantity.calculateMaxFuelQuantity(fuelQuantityPlan3));
}
}
В этом классе объявляется и инициализируется каждый экземпляр класса получателя, включая исходный класс, если он реализован разработчиком.
Он устанавливает преемников для каждого класса получателя.
Преимущества шаблона проектирования цепочки ответственности:
· Разработчик может изменить структуру или порядок получателей и отправителей, не манипулируя базовой реализацией. В результате этого повышается гибкость возложенных на объект обязанностей.
Недостатки шаблона проектирования цепочки ответственности:
· Не гарантируется получение объекта соответствующим получателем.
· Производительность системы будет затронута, но и отладка кода не является легкой задачей.
Я надеюсь, что теперь вы можете понять, что такое шаблон проектирования цепочки ответственности, как реализовать цепочку ответственности, когда ее использовать и каковы ее преимущества и недостатки.