Шаблон проектирования цепочки ответственности в Java
Шаблон проектирования цепочки ответственности является одним из шаблонов поведенческого проектирования.
Шаблон проектирования цепочки ответственности
Пример шаблона цепочки ответственности в JDK
Давайте посмотрим на пример шаблона цепочки ответственности в JDK, а затем приступим к реализации реального примера этого шаблона. Мы знаем, что у нас может быть несколько блоков catch в коде блока try-catch. Здесь каждый блок catch является своего рода процессором для обработки этого конкретного исключения. Поэтому, когда в блоке try возникает какое-либо исключение, оно отправляется в первый блок catch для обработки. Если блок catch не может его обработать, он перенаправляет запрос следующему объекту в цепочке, то есть следующему блоку catch. Если даже последний блок catch не может его обработать, исключение выбрасывается за пределы цепочки вызывающей программе.
Пример шаблона проектирования цепочки ответственности
Шаблон проектирования цепочки ответственности — базовые классы и интерфейс
Мы можем создать класс Currency
, в котором будет храниться сумма для выдачи и использования реализацией цепочки. Валюта.java
package com.journaldev.design.chainofresponsibility;
public class Currency {
private int amount;
public Currency(int amt){
this.amount=amt;
}
public int getAmount(){
return this.amount;
}
}
Базовый интерфейс должен иметь метод для определения следующего процессора в цепочке и метод, который будет обрабатывать запрос. Наш интерфейс ATM Dispense будет выглядеть так, как показано ниже. DispenseChain.java
package com.journaldev.design.chainofresponsibility;
public interface DispenseChain {
void setNextChain(DispenseChain nextChain);
void dispense(Currency cur);
}
Шаблон цепочки ответственности — реализация цепочки
Нам нужно создать разные классы процессоров, которые будут реализовывать интерфейс DispenseChain
и обеспечивать реализацию методов дозирования. Так как мы разрабатываем нашу систему для работы с тремя типами денежных купюр - 50$, 20$и 10$, мы создадим три конкретных реализации. Dollar50Dispenser.java
package com.journaldev.design.chainofresponsibility;
public class Dollar50Dispenser implements DispenseChain {
private DispenseChain chain;
@Override
public void setNextChain(DispenseChain nextChain) {
this.chain=nextChain;
}
@Override
public void dispense(Currency cur) {
if(cur.getAmount() >= 50){
int num = cur.getAmount()/50;
int remainder = cur.getAmount() % 50;
System.out.println("Dispensing "+num+" 50$ note");
if(remainder !=0) this.chain.dispense(new Currency(remainder));
}else{
this.chain.dispense(cur);
}
}
}
Dollar20Dispenser.java
package com.journaldev.design.chainofresponsibility;
public class Dollar20Dispenser implements DispenseChain{
private DispenseChain chain;
@Override
public void setNextChain(DispenseChain nextChain) {
this.chain=nextChain;
}
@Override
public void dispense(Currency cur) {
if(cur.getAmount() >= 20){
int num = cur.getAmount()/20;
int remainder = cur.getAmount() % 20;
System.out.println("Dispensing "+num+" 20$ note");
if(remainder !=0) this.chain.dispense(new Currency(remainder));
}else{
this.chain.dispense(cur);
}
}
}
Dollar10Dispenser.java
package com.journaldev.design.chainofresponsibility;
public class Dollar10Dispenser implements DispenseChain {
private DispenseChain chain;
@Override
public void setNextChain(DispenseChain nextChain) {
this.chain=nextChain;
}
@Override
public void dispense(Currency cur) {
if(cur.getAmount() >= 10){
int num = cur.getAmount()/10;
int remainder = cur.getAmount() % 10;
System.out.println("Dispensing "+num+" 10$ note");
if(remainder !=0) this.chain.dispense(new Currency(remainder));
}else{
this.chain.dispense(cur);
}
}
}
Здесь важно отметить реализацию метода дозирования. Вы заметите, что каждая реализация пытается обработать запрос и, в зависимости от суммы, может обработать часть или всю его часть. Если один из участников цепочки не может обработать его полностью, он отправляет запрос следующему процессору в цепочке для обработки оставшегося запроса. Если процессор не может ничего обработать, он просто пересылает тот же запрос в следующую цепочку.
Шаблон проектирования «Цепь ответственности» — создание цепочки
Это очень важный шаг, и мы должны тщательно создавать цепочку, иначе процессор может вообще не получить никакого запроса. Например, в нашей реализации, если мы сохраним цепочку первого процессора как Dollar10Dispenser
, а затем Dollar20Dispenser
, то запрос никогда не будет перенаправлен на второй процессор, и цепочка станет бесполезной. . Вот наша реализация ATM Dispenser для обработки запрошенной пользователем суммы. ATMDispenseChain.java
package com.journaldev.design.chainofresponsibility;
import java.util.Scanner;
public class ATMDispenseChain {
private DispenseChain c1;
public ATMDispenseChain() {
// initialize the chain
this.c1 = new Dollar50Dispenser();
DispenseChain c2 = new Dollar20Dispenser();
DispenseChain c3 = new Dollar10Dispenser();
// set the chain of responsibility
c1.setNextChain(c2);
c2.setNextChain(c3);
}
public static void main(String[] args) {
ATMDispenseChain atmDispenser = new ATMDispenseChain();
while (true) {
int amount = 0;
System.out.println("Enter amount to dispense");
Scanner input = new Scanner(System.in);
amount = input.nextInt();
if (amount % 10 != 0) {
System.out.println("Amount should be in multiple of 10s.");
return;
}
// process the request
atmDispenser.c1.dispense(new Currency(amount));
}
}
}
Когда мы запускаем вышеуказанное приложение, мы получаем вывод, как показано ниже.
Enter amount to dispense
530
Dispensing 10 50$ note
Dispensing 1 20$ note
Dispensing 1 10$ note
Enter amount to dispense
100
Dispensing 2 50$ note
Enter amount to dispense
120
Dispensing 2 50$ note
Dispensing 1 20$ note
Enter amount to dispense
15
Amount should be in multiple of 10s.
Диаграмма классов шаблона проектирования цепи ответственности
Важные моменты шаблона проектирования цепочки ответственности
- Клиент не знает, какая часть цепочки будет обрабатывать запрос, и отправит запрос первому объекту в цепочке. Например, в нашей программе ATMDispenseChain не знает, кто обрабатывает запрос на выдачу введенной суммы.
- Каждый объект в цепочке будет иметь собственную реализацию для обработки запроса, полного или частичного, или для отправки его следующему объекту в цепочке.
- Каждый объект в цепочке должен иметь ссылку на следующий объект в цепочке для пересылки запроса, что достигается композицией Java.
- Тщательно создавать цепочку очень важно, иначе может случиться так, что запрос никогда не будет перенаправлен конкретному процессору или в цепочке не будет объектов, способных обработать запрос. В моей реализации я добавил проверку введенной пользователем суммы, чтобы убедиться, что она полностью обрабатывается всеми процессорами, но мы можем не проверять ее и выдавать исключение, если запрос достигает последнего объекта и в цепочке нет других объектов. для переадресации запроса. Это дизайнерское решение.
- Шаблон проектирования Цепочка ответственности хорош для достижения потери связи, но он сопряжен с необходимостью иметь множество классов реализации и проблемами сопровождения, если большая часть кода является общей во всех реализациях.
Примеры шаблонов цепочки ответственности в JDK
- java.util.logging.Logger#log()
- javax.servlet.Filter#doFilter()
Вот и все, что касается шаблона проектирования «Цепочка ответственности». Я надеюсь, он вам понравился и поможет прояснить ваше понимание этого шаблона проектирования.