NOTE
Chain of Responsibility
The chain-of-responsibility pattern links handlers that can process the same type of request, with Java, Go, and filter-chain examples.
This is a historical learning note and may contain outdated or incomplete understanding.
1. Definition
Connect objects that can handle the same type of request into a chain, such as servlet filters.
2. UML
3. Java
3.1. Client
public class Client
{
public static void main(String[] args)
{
LeaveRequest request = new LeaveRequest(2);
Leader boss = new Boss(null);
Leader manager = new Manager(boss);
manager.handlerRequest(request);
}
}
3.2. Processing Chain
public abstract class Leader
{
protected Leader nextLeader;
public Leader(Leader nextLeader)
{
this.nextLeader = nextLeader;
}
public abstract void handlerRequest(LeaveRequest request);
}
public class Boss extends Leader
{
public Boss(Leader nextLeader)
{
super(nextLeader);
}
@Override
public void handlerRequest(LeaveRequest request)
{
if (request.getLeaverDays() < 30)
System.out.println("Boss approves");
else
{
if (this.nextLeader != null)
this.nextLeader.handlerRequest(request);
System.out.println("Rejected");
}
}
}
public class Manager extends Leader
{
public Manager(Leader nextLeader)
{
super(nextLeader);
}
@Override
public void handlerRequest(LeaveRequest request)
{
if (request.getLeaverDays() < 3)
System.out.println("Manager approves");
else
{
if (this.nextLeader != null)
this.nextLeader.handlerRequest(request);
}
}
}
3.3. Request
public class LeaveRequest
{
private int leaverDays;
public LeaveRequest(int leaverDays)
{
this.leaverDays = leaverDays;
}
public int getLeaverDays()
{
return leaverDays;
}
public void setLeaverDays(int leaverDays)
{
this.leaverDays = leaverDays;
}
}
4. Golang
4.1. Client
func main() {
boss := 责任链.NewBoss()
deptLeader := 责任链.NewDeptLeader()
teamLeader := 责任链.NewTeamLeader()
teamLeader.SetSuccessor(deptLeader)
deptLeader.SetSuccessor(boss)
request := 责任链.NewVacationRequest(5)
teamLeader.HandleVocationRequest(request)
}
4.2. Processing Chain
/* Manager interface */
type IManager interface {
SetSuccessor(IManager)
HandleVocationRequest(*VacationRequest) bool
}
/* Base manager implementation */
type BaseManager struct {
Successor IManager
}
func (m *BaseManager) SetSuccessor(manager IManager) {
m.Successor = manager
}
func (m *BaseManager) HandleVocationRequest(request *VacationRequest) bool {
return false
}
type TeamLeader struct {
BaseManager
}
func NewTeamLeader() *TeamLeader {
return &TeamLeader{}
}
func (t *TeamLeader) HandleVocationRequest(request *VacationRequest) bool {
if request.Day < 3 {
fmt.Printf("TeamLeader approves leave request [%d]
", request.Day)
return true
} else if t.Successor != nil {
fmt.Printf("TeamLeader is not authorized to approve leave request [%d], pass it to [%s]
", request.Day, "the next approver")
t.Successor.HandleVocationRequest(request)
}
return false
}
type DeptLeader struct {
BaseManager
}
func NewDeptLeader() *DeptLeader {
return &DeptLeader{}
}
func (t *DeptLeader) HandleVocationRequest(request *VacationRequest) bool {
if request.Day < 10 {
fmt.Printf("DeptLeader approves leave request [%d]
", request.Day)
return true
} else if t.Successor != nil {
fmt.Printf("DeptLeader is not authorized to approve leave request [%d], pass it to [%s]
", request.Day, "the next approver")
t.Successor.HandleVocationRequest(request)
}
return false
}
type Boss struct {
BaseManager
}
func NewBoss() *Boss {
return &Boss{}
}
func (t *Boss) HandleVocationRequest(request *VacationRequest) bool {
fmt.Printf("Boss approves leave request [%d]
", request.Day)
return true
}
4.3. Request
/* Leave request */
type VacationRequest struct {
Day uint32
}
func NewVacationRequest(day uint32) *VacationRequest {
return &VacationRequest{Day: day}
}
5. Example
5.1. Filter Chain
type Config struct {
key string
value string
}
// Filter function
type filterFunc func(config *Config) bool
// Filter chain
type FilterChain struct {
filterChains []filterFunc
}
// Add a filter
func (f *FilterChain) addFilter(filter filterFunc) {
f.filterChains = append(f.filterChains, filter)
}
// Execute the filters
func (f *FilterChain) filter(config *Config) bool {
for _, filter := range f.filterChains {
if filter(config) {
return true
}
}
return false
}
// Key filter
func keyFilter(config *Config) bool {
if config.key == "name" {
return true
}
return false
}
// Value filter
func valueFilter(config *Config) bool {
if config.value == "[REDACTED]" {
return true
}
return false
}
var defaultFilterChain = &FilterChain{}
func init() {
defaultFilterChain.addFilter(keyFilter)
defaultFilterChain.addFilter(valueFilter)
}
func main() {
fmt.Println(defaultFilterChain.filter(&Config{}) == false)
fmt.Println(defaultFilterChain.filter(&Config{key: "key"}) == false)
fmt.Println(defaultFilterChain.filter(&Config{key: "name"}) == true)
fmt.Println(defaultFilterChain.filter(&Config{value: "[REDACTED]"}) == true)
fmt.Println(defaultFilterChain.filter(&Config{value: "example"}) == false)
}
Discussion
Sign in with GitHub to comment. Discussions are stored as GitHub Issues.View on GitHub