Skip to content

Commit 61c0bb5

Browse files
authored
Merge pull request #8 from ahucoder/dev
The Chain of Responsibility Pattern
2 parents 8253ccb + 3bb43ce commit 61c0bb5

File tree

12 files changed

+262
-0
lines changed

12 files changed

+262
-0
lines changed

src/main/java/chain/App.java

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package chain;
2+
3+
import chain.dto.ApprovalRequestDto;
4+
import chain.enums.RequestType;
5+
import chain.handler.ApprovalHandler;
6+
import chain.processor.CEO;
7+
import chain.processor.DepartmentManager;
8+
import chain.processor.HRManager;
9+
10+
public class App {
11+
public static void main(String[] args) {
12+
// Chain:deptManager -> hrManager -> CEO
13+
ApprovalHandler deptManager = new DepartmentManager();
14+
ApprovalHandler hrManager = new HRManager();
15+
ApprovalHandler ceo = new CEO();
16+
17+
deptManager.linkWith(hrManager).linkWith(ceo);
18+
19+
// Different scene requests
20+
ApprovalRequestDto r1 = new ApprovalRequestDto(RequestType.LEAVE, "Alice", 0, 2);
21+
ApprovalRequestDto r2 = new ApprovalRequestDto(RequestType.EXPENSE, "Bob", 800, 0);
22+
ApprovalRequestDto r3 = new ApprovalRequestDto(RequestType.PURCHASE, "Charlie", 5000, 0);
23+
ApprovalRequestDto r4 = new ApprovalRequestDto(RequestType.LEAVE, "David", 0, 10);
24+
25+
System.out.println("--- Start processing requests ---");
26+
System.out.printf("--- r1 start [%s]---%n", r1.getType());
27+
deptManager.handle(r1);
28+
System.out.printf("--- r1 end [%s]---%n", r1.getType());
29+
System.out.printf("--- r2 start [%s]---%n", r2.getType());
30+
deptManager.handle(r2);
31+
System.out.printf("--- r2 end [%s]---%n", r2.getType());
32+
System.out.printf("--- r3 start [%s]---%n", r3.getType());
33+
deptManager.handle(r3);
34+
System.out.printf("--- r3 end [%s]---%n", r3.getType());
35+
System.out.printf("--- r4 start [%s]---%n", r4.getType());
36+
deptManager.handle(r4);
37+
System.out.printf("--- r4 end [%s]---%n", r4.getType());
38+
39+
System.out.println("--- Request processing completed ---");
40+
}
41+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package chain.dto;
2+
3+
import chain.enums.RequestType;
4+
import lombok.AllArgsConstructor;
5+
import lombok.Getter;
6+
7+
@AllArgsConstructor
8+
@Getter
9+
public class ApprovalRequestDto {
10+
private final RequestType type;
11+
private final String applicant;
12+
private final double amount;
13+
private final int days;
14+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package chain.enums;
2+
3+
public enum RequestType {
4+
LEAVE("Leave Application"),
5+
EXPENSE("Expense Reimbursement "),
6+
PURCHASE("Procurement Request"),
7+
;
8+
9+
private final String typeName;
10+
11+
RequestType(String typeName) {
12+
this.typeName = typeName;
13+
}
14+
15+
/**
16+
* Get a description of the type
17+
* @return description of the type
18+
*/
19+
public String getType() {
20+
return typeName;
21+
}
22+
23+
/**
24+
* Search for the corresponding enumeration value based on the string (case-insensitive)
25+
* @param typeStr Type string
26+
* @return Corresponding enumeration values
27+
* @throws IllegalArgumentException If no matching enumeration value can be found
28+
*/
29+
public static RequestType fromString(String typeStr) {
30+
for (RequestType type : values()) {
31+
if (type.typeName.equalsIgnoreCase(typeStr)
32+
|| type.name().equalsIgnoreCase(typeStr)) {
33+
return type;
34+
}
35+
}
36+
throw new IllegalArgumentException("Invalid request type: " + typeStr);
37+
}
38+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package chain.handler;
2+
3+
import chain.dto.ApprovalRequestDto;
4+
import chain.service.ApprovalRuleService;
5+
6+
import java.util.List;
7+
8+
public abstract class ApprovalHandler {
9+
protected ApprovalHandler next;
10+
private final List<ApprovalRuleService> rules;
11+
12+
public ApprovalHandler(List<ApprovalRuleService> rules) {
13+
this.rules = rules;
14+
}
15+
16+
//pipeline
17+
public ApprovalHandler linkWith(ApprovalHandler next) {
18+
this.next = next;
19+
return next;
20+
}
21+
22+
public void handle(ApprovalRequestDto request) {
23+
if (rules.stream().anyMatch(rule -> rule.evaluate(request))) {
24+
System.out.printf("[%s]Approve the %s application for %s: days=%d, amount=%.2f%n",
25+
getClass().getSimpleName(), request.getApplicant(), request.getType(),
26+
request.getDays(), request.getAmount());
27+
} else {
28+
System.out.printf("[%s]Not in compliance with approval rules, transferred to the next level: %s%n",
29+
getClass().getSimpleName(), next != null ? next.getClass().getSimpleName() : "Null");
30+
passToNext(request);
31+
}
32+
}
33+
34+
protected void passToNext(ApprovalRequestDto request) {
35+
if (next != null) {
36+
next.handle(request);
37+
} else {
38+
System.out.println("[SYSTEM] No one can process this request: " + request.getType());
39+
}
40+
}
41+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package chain.processor;
2+
3+
import chain.handler.ApprovalHandler;
4+
import chain.service.impl.DefaultRuleService;
5+
6+
import java.util.List;
7+
8+
public class CEO extends ApprovalHandler {
9+
public CEO() {
10+
super(List.of(new DefaultRuleService()));
11+
}
12+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package chain.processor;
2+
3+
import chain.handler.ApprovalHandler;
4+
import chain.service.impl.LeaveDaysRuleService;
5+
6+
import java.util.List;
7+
8+
public class DepartmentManager extends ApprovalHandler {
9+
public DepartmentManager() {
10+
super(List.of(new LeaveDaysRuleService(3)));
11+
}
12+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package chain.processor;
2+
3+
import chain.handler.ApprovalHandler;
4+
import chain.service.impl.ExpenseAmountRuleService;
5+
import chain.service.impl.LeaveDaysRuleService;
6+
7+
import java.util.Arrays;
8+
9+
public class HRManager extends ApprovalHandler {
10+
public HRManager() {
11+
super(Arrays.asList(
12+
new LeaveDaysRuleService(7),
13+
new ExpenseAmountRuleService(1000)
14+
));
15+
}
16+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package chain.service;
2+
3+
import chain.dto.ApprovalRequestDto;
4+
5+
public interface ApprovalRuleService {
6+
boolean evaluate(ApprovalRequestDto request);
7+
8+
String getName();
9+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package chain.service.impl;
2+
3+
import chain.dto.ApprovalRequestDto;
4+
import chain.service.ApprovalRuleService;
5+
6+
public class DefaultRuleService implements ApprovalRuleService {
7+
@Override
8+
public boolean evaluate(ApprovalRequestDto request) {
9+
return true;
10+
}
11+
12+
@Override
13+
public String getName() {
14+
return "True";
15+
}
16+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package chain.service.impl;
2+
3+
import chain.dto.ApprovalRequestDto;
4+
import chain.enums.RequestType;
5+
import chain.service.ApprovalRuleService;
6+
7+
public class ExpenseAmountRuleService implements ApprovalRuleService {
8+
private final double maxAmount;
9+
10+
public ExpenseAmountRuleService(double maxAmount) {
11+
this.maxAmount = maxAmount;
12+
}
13+
14+
@Override
15+
public boolean evaluate(ApprovalRequestDto req) {
16+
return req.getType() == RequestType.EXPENSE && req.getAmount() <= maxAmount;
17+
}
18+
19+
@Override
20+
public String getName() {
21+
return "Expense<=" + maxAmount;
22+
}
23+
}

0 commit comments

Comments
 (0)