Поиск по сайту:

Шаблон проектирования цепочки ответственности в 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()

Вот и все, что касается шаблона проектирования «Цепочка ответственности». Я надеюсь, он вам понравился и поможет прояснить ваше понимание этого шаблона проектирования.