Java-Designmuster: Die Funktionsweise des Chain of Responsibility Patterns
Erfahren Sie, wie das Chain of Responsibility Design Pattern in Java eine effiziente und entkoppelte Anfragenverarbeitung ermöglicht. Von der Grundlagen bis zur praktischen Implementierung anhand eines ATM-Dispensersystems – entdecken Sie, wie dieses Muster die Codeorganisation verbessert. Tauchen Sie ein in die Welt der Verhaltensmuster und optimieren Sie Ihre Softwarearchitektur mit diesem umfassenden Überblick.
Beispiel für das Chain of Responsibility-Muster in der JDK
Ein Beispiel für das Chain of Responsibility-Muster in der JDK ist das Try-Catch-Blockcode, in dem mehrere Catch-Blöcke vorhanden sind, die jeweils eine bestimmte Ausnahme verarbeiten. Wenn eine Ausnahme im Try-Block auftritt, wird sie an den ersten Catch-Block gesendet, um verarbeitet zu werden. Und wenn der Catch-Block es nicht verarbeiten kann, leitet er die Anfrage an das nächste Objekt in der Kette weiter, den nächsten Catch-Block. Wenn auch der letzte Catch-Block es nicht verarbeiten kann, wird die Ausnahme außerhalb der Kette an das aufrufende Programm weitergegeben.
Beispiel für das Chain of Responsibility-Designmuster
Ein großartiges Beispiel für das Chain of Responsibility-Muster ist der Geldautomat. Der Benutzer gibt den auszugebenden Betrag ein, und der Geldautomat gibt den Betrag in Form von definierten Währungsscheinen wie 50 $, 20 $, 10 $ usw. aus. Wenn der Benutzer einen Betrag eingibt, der nicht durch 10 teilbar ist, wird ein Fehler gemeldet. Wir werden das Chain of Responsibility-Muster verwenden, um diese Lösung zu implementieren. Die Kette wird die Anfrage in der gleichen Reihenfolge wie im Diagramm unten verarbeiten. Beachten Sie, dass wir diese Lösung problemlos in einem einzigen Programm selbst implementieren könnten, aber dann würde die Komplexität zunehmen und die Lösung wäre stark gekoppelt. Daher erstellen wir eine Kette von Ausgabesystemen, um Scheine von 50 $, 20 $ und 10 $ auszugeben.
Basis-Klassen und Schnittstelle für das Chain of Responsibility-Designmuster
Wir können eine Klasse Currency erstellen, die den auszugebenden Betrag speichert und von den Kettenimplementierungen verwendet wird. Die Basisschnittstelle sollte eine Methode haben, um den nächsten Prozessor in der Kette zu definieren, und die Methode, die die Anfrage verarbeitet. Unsere ATM-Dispenserschnittstelle sieht wie folgt aus.
package com.journaldev.design.chainofresponsibility;
public class Currency {
private int amount;
public Currency(int amt){
this.amount=amt;
}
public int getAmount(){
return this.amount;
}
}
package com.journaldev.design.chainofresponsibility;
public interface DispenseChain {
void setNextChain(DispenseChain nextChain);
void dispense(Currency cur);
}
Kettenimplementierungen des Chain of Responsibility-Musters
Es müssen verschiedene Prozessorklassen erstellt werden, die das DispenseChain-Interface implementieren und die Implementierung der Dispense-Methoden bereitstellen. Da wir unser System entwickeln, um mit drei Arten von Währungsscheinen zu arbeiten – 50 $, 20 $ und 10 $ -, werden wir drei konkrete Implementierungen erstellen.
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);
}
}
}
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);
}
}
}
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);
}
}
}
Erstellen der Kette für das Chain of Responsibility-Designmuster
Dies ist ein sehr wichtiger Schritt, und wir sollten die Kette sorgfältig erstellen, da sonst ein Prozessor möglicherweise überhaupt keine Anfragen erhält.
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));
}
}
}
Wichtige Punkte des Chain of Responsibility-Designmusters
- Der Client weiß nicht, welcher Teil der Kette die Anfrage verarbeitet. Also sendet er die Anfrage an das erste Objekt in der Kette.
- Jedes Objekt in der Kette hat seine eigene Implementierung zur Verarbeitung der Anfrage, entweder vollständig oder teilweise, oder um sie an das nächste Objekt in der Kette zu senden.
- Jedes Objekt in der Kette sollte eine Referenz auf das nächste Objekt in der Kette haben, um die Anfrage weiterzuleiten.
Beispiele für das Chain of Responsibility-Muster in JDK
- java.util.logging.Logger#log()
- javax.servlet.Filter#doFilter()
Das war alles zum Chain of Responsibility-Designmuster. Ich hoffe, es hat Ihnen gefallen und dazu beigetragen, Ihr Verständnis für dieses Entwurfsmuster zu klären.