웹사이트 검색

Java의 책임 사슬 디자인 패턴


책임 사슬 디자인 패턴은 행동 디자인 패턴 중 하나입니다.

책임 사슬 디자인 패턴

JDK의 책임 사슬 패턴 예제

JDK에서 책임 사슬 패턴의 예를 본 다음 이 패턴의 실제 예를 구현해 보겠습니다. 우리는 try-catch 블록 코드에 여러 개의 catch 블록을 가질 수 있다는 것을 알고 있습니다. 여기서 모든 catch 블록은 특정 예외를 처리하는 일종의 프로세서입니다. 따라서 try 블록에서 예외가 발생하면 처리할 첫 번째 catch 블록으로 보냅니다. catch 블록이 처리할 수 없는 경우 체인의 다음 개체, 즉 다음 catch 블록으로 요청을 전달합니다. 마지막 catch 블록도 처리할 수 없는 경우 체인 외부에서 호출 프로그램으로 예외가 throw됩니다.

책임 사슬 디자인 패턴 예제

책임 사슬 디자인 패턴 - 기본 클래스 및 인터페이스

분배할 양을 저장하고 체인 구현에서 사용할 클래스 Currency를 만들 수 있습니다. 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 구성에 의해 달성됩니다.
  • 체인을 신중하게 만드는 것은 매우 중요합니다. 그렇지 않으면 요청이 특정 프로세서로 전달되지 않거나 체인에 요청을 처리할 수 있는 개체가 없는 경우가 있을 수 있습니다. 내 구현에서 모든 프로세서에 의해 완전히 처리되는지 확인하기 위해 사용자가 입력한 양에 대한 검사를 추가했지만 요청이 마지막 개체에 도달하고 체인에 더 이상의 개체가 없는 경우 확인하지 않고 예외를 throw할 수 있습니다. 요청을 전달합니다. 이것은 디자인 결정입니다.
  • 책임 사슬 디자인 패턴은 결합을 잃기에는 좋지만 대부분의 코드가 모든 구현에서 공통적인 경우 구현 클래스가 많고 유지 관리 문제가 있다는 단점이 있습니다.

JDK의 책임 사슬 패턴 예

  • java.util.logging.Logger#log()
  • javax.servlet.Filter#doFilter()

이것이 책임 사슬 디자인 패턴의 전부입니다. 당신이 그것을 좋아하고 이 디자인 패턴에 대한 이해를 명확히 할 수 있기를 바랍니다.