diff --git a/chain/README.md b/chain/README.md index f5f6c9de9..1d7eb5b73 100644 --- a/chain/README.md +++ b/chain/README.md @@ -16,7 +16,131 @@ Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it. -![alt text](./etc/chain_1.png "Chain of Responsibility") +## Explanation + +Real world example + +> The Orc King gives loud orders to his army. The closest one to react is the commander, then officer and then soldier. The commander, officer and soldier here form a chain of responsibility. + +In plain words + +> It helps building a chain of objects. Request enters from one end and keeps going from object to object till it finds the suitable handler. + +Wikipedia says + +> In object-oriented design, the chain-of-responsibility pattern is a design pattern consisting of a source of command objects and a series of processing objects. Each processing object contains logic that defines the types of command objects that it can handle; the rest are passed to the next processing object in the chain. + +**Programmatic Example** + +Translating our example with orcs from above. First we have the request class + +``` +public class Request { + + private final RequestType requestType; + private final String requestDescription; + private boolean handled; + + public Request(final RequestType requestType, final String requestDescription) { + this.requestType = Objects.requireNonNull(requestType); + this.requestDescription = Objects.requireNonNull(requestDescription); + } + + public String getRequestDescription() { return requestDescription; } + + public RequestType getRequestType() { return requestType; } + + public void markHandled() { this.handled = true; } + + public boolean isHandled() { return this.handled; } + + @Override + public String toString() { return getRequestDescription(); } +} + +public enum RequestType { + DEFEND_CASTLE, TORTURE_PRISONER, COLLECT_TAX +} +``` + +Then the request handler hierarchy + +``` +public abstract class RequestHandler { + private static final Logger LOGGER = LoggerFactory.getLogger(RequestHandler.class); + private RequestHandler next; + + public RequestHandler(RequestHandler next) { + this.next = next; + } + + public void handleRequest(Request req) { + if (next != null) { + next.handleRequest(req); + } + } + + protected void printHandling(Request req) { + LOGGER.info("{} handling request \"{}\"", this, req); + } + + @Override + public abstract String toString(); +} + +public class OrcCommander extends RequestHandler { + public OrcCommander(RequestHandler handler) { + super(handler); + } + + @Override + public void handleRequest(Request req) { + if (req.getRequestType().equals(RequestType.DEFEND_CASTLE)) { + printHandling(req); + req.markHandled(); + } else { + super.handleRequest(req); + } + } + + @Override + public String toString() { + return "Orc commander"; + } +} + +// OrcOfficer and OrcSoldier are defined similarly as OrcCommander + +``` + +Then we have the Orc King who gives the orders and forms the chain + +``` +public class OrcKing { + RequestHandler chain; + + public OrcKing() { + buildChain(); + } + + private void buildChain() { + chain = new OrcCommander(new OrcOfficer(new OrcSoldier(null))); + } + + public void makeRequest(Request req) { + chain.handleRequest(req); + } +} +``` + +Then it is used as follows + +``` +OrcKing king = new OrcKing(); +king.makeRequest(new Request(RequestType.DEFEND_CASTLE, "defend castle")); // Orc commander handling request "defend castle" +king.makeRequest(new Request(RequestType.TORTURE_PRISONER, "torture prisoner")); // Orc officer handling request "torture prisoner" +king.makeRequest(new Request(RequestType.COLLECT_TAX, "collect tax")); // Orc soldier handling request "collect tax" +``` ## Applicability Use Chain of Responsibility when diff --git a/chain/etc/chain.png b/chain/etc/chain.png deleted file mode 100644 index 7316ff3d0..000000000 Binary files a/chain/etc/chain.png and /dev/null differ diff --git a/chain/etc/chain.ucls b/chain/etc/chain.ucls deleted file mode 100644 index 4f82b40c7..000000000 --- a/chain/etc/chain.ucls +++ /dev/null @@ -1,109 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/chain/etc/chain.urm.puml b/chain/etc/chain.urm.puml deleted file mode 100644 index 4a2f6a188..000000000 --- a/chain/etc/chain.urm.puml +++ /dev/null @@ -1,61 +0,0 @@ -@startuml -package com.iluwatar.chain { - class App { - + App() - + main(args : String[]) {static} - } - class OrcCommander { - + OrcCommander(handler : RequestHandler) - + handleRequest(req : Request) - + toString() : String - } - class OrcKing { - ~ chain : RequestHandler - + OrcKing() - - buildChain() - + makeRequest(req : Request) - } - class OrcOfficer { - + OrcOfficer(handler : RequestHandler) - + handleRequest(req : Request) - + toString() : String - } - class OrcSoldier { - + OrcSoldier(handler : RequestHandler) - + handleRequest(req : Request) - + toString() : String - } - class Request { - - handled : boolean - - requestDescription : String - - requestType : RequestType - + Request(requestType : RequestType, requestDescription : String) - + getRequestDescription() : String - + getRequestType() : RequestType - + isHandled() : boolean - + markHandled() - + toString() : String - } - abstract class RequestHandler { - - LOGGER : Logger {static} - - next : RequestHandler - + RequestHandler(next : RequestHandler) - + handleRequest(req : Request) - # printHandling(req : Request) - + toString() : String {abstract} - } - enum RequestType { - + COLLECT_TAX {static} - + DEFEND_CASTLE {static} - + TORTURE_PRISONER {static} - + valueOf(name : String) : RequestType {static} - + values() : RequestType[] {static} - } -} -RequestHandler --> "-next" RequestHandler -Request --> "-requestType" RequestType -OrcKing --> "-chain" RequestHandler -OrcCommander --|> RequestHandler -OrcOfficer --|> RequestHandler -OrcSoldier --|> RequestHandler -@enduml \ No newline at end of file diff --git a/chain/etc/chain_1.png b/chain/etc/chain_1.png deleted file mode 100644 index fe9e3d6ed..000000000 Binary files a/chain/etc/chain_1.png and /dev/null differ diff --git a/pom.xml b/pom.xml index f2b6b7ccb..840c14eca 100644 --- a/pom.xml +++ b/pom.xml @@ -473,6 +473,8 @@ decorator facade flyweight + proxy + chain diff --git a/proxy/etc/proxy.png b/proxy/etc/proxy.png deleted file mode 100644 index 300e58dd3..000000000 Binary files a/proxy/etc/proxy.png and /dev/null differ diff --git a/proxy/etc/proxy.ucls b/proxy/etc/proxy.ucls deleted file mode 100644 index 76b5f0160..000000000 --- a/proxy/etc/proxy.ucls +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/proxy/etc/proxy.urm.puml b/proxy/etc/proxy.urm.puml deleted file mode 100644 index ffe0fa446..000000000 --- a/proxy/etc/proxy.urm.puml +++ /dev/null @@ -1,32 +0,0 @@ -@startuml -package com.iluwatar.proxy { - class App { - + App() - + main(args : String[]) {static} - } - class IvoryTower { - - LOGGER : Logger {static} - + IvoryTower() - + enter(wizard : Wizard) - } - class Wizard { - - name : String - + Wizard(name : String) - + toString() : String - } - interface WizardTower { - + enter(Wizard) {abstract} - } - class WizardTowerProxy { - - LOGGER : Logger {static} - - NUM_WIZARDS_ALLOWED : int {static} - - numWizards : int - - tower : WizardTower - + WizardTowerProxy(tower : WizardTower) - + enter(wizard : Wizard) - } -} -WizardTowerProxy --> "-tower" WizardTower -IvoryTower ..|> WizardTower -WizardTowerProxy ..|> WizardTower -@enduml \ No newline at end of file