设计模式 - 代理模式
设计模式 - 命令模式

设计模式 - 责任链模式

violet posted @ 5 年前 in 笔记 with tags Design Pattern Golang , 237 阅读

意图:避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。

主要解决:职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递,所以职责链将请求的发送者和请求的处理者解耦了。

何时使用:在处理消息的时候以过滤很多道。

如何解决:拦截的类都实现统一接口。

关键代码:Handler 里面聚合它自己,在 HandlerRequest 里判断是否合适,如果没达到条件则向下传递,向谁传递之前 set 进去。

应用实例: 1、红楼梦中的"击鼓传花"。 2、JS 中的事件冒泡。 3、JAVA WEB 中 Apache Tomcat 对 Encoding 的处理,Struts2 的拦截器,jsp servlet 的 Filter。

优点: 1、降低耦合度。它将请求的发送者和接收者解耦。 2、简化了对象。使得对象不需要知道链的结构。 3、增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。 4、增加新的请求处理类很方便。

缺点: 1、不能保证请求一定被接收。 2、系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用。 3、可能不容易观察运行时的特征,有碍于除错。

使用场景: 1、有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定。 2、在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。 3、可动态指定一组对象处理请求。

注意事项:在 JAVA WEB 中遇到很多应用。

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package main
 
import "fmt"
 
const (
    INFO  = 1
    DEBUG = 2
    ERROR = 3
)
 
type ConsoleLogger struct {
    Level      int
    NextLogger interface{}
}
 
func NewConsoleLogger(level int) *ConsoleLogger {
    return &ConsoleLogger{
        Level: level,
    }
}
 
func (a *ConsoleLogger) LogMessage(level int, message string) {
    if a.Level == level {
        a.Write(message)
        return
    }
    if a.NextLogger != nil {
        switch v := a.NextLogger.(type) {
        case *ErrorLogger:
            v.LogMessage(level, message)
        case *ConsoleLogger:
            v.LogMessage(level, message)
        case *FileLogger:
            v.LogMessage(level, message)
        }
    }
}
 
func (c *ConsoleLogger) Write(message string) {
    fmt.Println("stdout: ", message)
}
 
type ErrorLogger struct {
    Level      int
    NextLogger interface{}
}
 
func NewErrorLogger(level int) *ErrorLogger {
    return &ErrorLogger{
        Level: level,
    }
}
 
func (a *ErrorLogger) LogMessage(level int, message string) {
    if a.Level == level {
        a.Write(message)
        return
    }
    if a.NextLogger != nil {
        switch v := a.NextLogger.(type) {
        case *ErrorLogger:
            v.LogMessage(level, message)
        case *ConsoleLogger:
            v.LogMessage(level, message)
        case *FileLogger:
            v.LogMessage(level, message)
        }
    }
}
 
func (e *ErrorLogger) Write(message string) {
    fmt.Println("stderr: ", message)
}
 
type FileLogger struct {
    Level      int
    NextLogger interface{}
}
 
func NewFileLogger(level int) *FileLogger {
    return &FileLogger{
        Level: level,
    }
}
 
func (a *FileLogger) LogMessage(level int, message string) {
    if a.Level == level {
        a.Write(message)
        return
    }
    if a.NextLogger != nil {
        switch v := a.NextLogger.(type) {
        case *ErrorLogger:
            v.LogMessage(level, message)
        case *ConsoleLogger:
            v.LogMessage(level, message)
        case *FileLogger:
            v.LogMessage(level, message)
        }
    }
}
 
func (f *FileLogger) Write(message string) {
    fmt.Println("file logger: ", message)
}
 
func main() {
    console := &ConsoleLogger{
        Level: INFO,
    }
    err := &ErrorLogger{
        Level: ERROR,
    }
    file := &FileLogger{
        Level: DEBUG,
    }
 
    chain := &ConsoleLogger{
        Level:      INFO,
        NextLogger: console,
    }
    chain.NextLogger.(*ConsoleLogger).NextLogger = err
    chain.NextLogger.(*ConsoleLogger).NextLogger.(*ErrorLogger).NextLogger = file
 
    chain.LogMessage(DEBUG, "This is a debug info")
    chain.LogMessage(ERROR, "This is an error info")
    chain.LogMessage(INFO, "This is an info")
}

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter