Design Patterns(十四):Chain of Responsibility--VB代码
★★☆☆☆
为使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
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.
结构图

角色
- 抽象处理者(Subject)角色:定义出一个处理请求的接口。 根据需要可以定义出一个设定和返回对下家引用的方法。这个角色通常由一个抽象类或接口实现。
- 代理主题(Proxy)角色:处理可以处理的请求,将不能处理的请求传递给下家。
动机
在软件构建过程中,一个请求可能被多个对象处理,但是每个请求在运行时只能有一个接受者,如果显式指定,将必不可少地带来请求发送者与接受者的紧耦合。如何使请求的发送者不需要指定具体的接受者?让请求的接受者自己在运行时决定来处理请求,从而使两者解耦。
意图
为使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
示意性代码


'Chain of Responsibility pattern -- Structural example
Public Class MainApp
'MainApp test application
Public Shared Sub Main()
'Setup Chain of Responsibility
Dim h1 As Handler = New ConcreteHandler1
Dim h2 As Handler = New ConcreteHandler2
Dim h3 As Handler = New ConcreteHandler3
h1.SetSuccessor(h2)
h2.SetSuccessor(h3)
'Generate and process request
Dim requests() As Integer = {2, 5, 14, 22, 18, 3, 27, 20}
For Each request As Integer In requests
h1.HandleRequest(request)
Next
'Wait for user
Console.ReadLine()
End Sub
End Class
'"Handler"
Public MustInherit Class Handler
Protected successor As Handler
Public Sub SetSuccessor(ByVal successor As Handler)
Me.successor = successor
End Sub
Public MustOverride Sub HandleRequest(ByVal request As Integer)
End Class
'"ConcreteHandler"
Public Class ConcreteHandler1
Inherits Handler
Public Overrides Sub HandleRequest(ByVal request As Integer)
If request > 0 And request < 10 Then
Console.WriteLine("{0} handled request {1}", Me.GetType().Name, request)
ElseIf successor IsNot Nothing Then
successor.HandleRequest(request)
End If
End Sub
End Class
'"ConcreteHandler"
Public Class ConcreteHandler2
Inherits Handler
Public Overrides Sub HandleRequest(ByVal request As Integer)
If request > 10 And request < 20 Then
Console.WriteLine("{0} handled request {1}", Me.GetType().Name, request)
ElseIf successor IsNot Nothing Then
successor.HandleRequest(request)
End If
End Sub
End Class
'"ConcreteHandler"
Public Class ConcreteHandler3
Inherits Handler
Public Overrides Sub HandleRequest(ByVal request As Integer)
If request > 20 And request < 30 Then
Console.WriteLine("{0} handled request {1}", Me.GetType().Name, request)
ElseIf successor IsNot Nothing Then
successor.HandleRequest(request)
End If
End Sub
End Class
一个实例
下面的责任链代码演示了不同职务的人根据所设定的权限对一个购买请求作出决策或将其交给更高的决策者。


'MainApp test application
Public Class MainApp
Private Shared Sub Main()
'Setup Chain of Responsibility
Dim Larry As New Director()
Dim Sam As New VicePresident()
Dim Tammy As New President()
Larry.SetSuccessor(Sam)
Sam.SetSuccessor(Tammy)
'Generate and process purchase requests
Dim p As New Purchase(2034, 350, "Supplies")
Larry.ProcessRequest(p)
p = New Purchase(2035, 32590.1, "Project X")
Larry.ProcessRequest(p)
p = New Purchase(2036, 122100, "Project Y")
Larry.ProcessRequest(p)
' Wait for user
Console.Read()
End Sub
End Class
' "Handler"
Public MustInherit Class Approver
Protected successor As Approver
Public Sub SetSuccessor(ByVal successor As Approver)
Me.successor = successor
End Sub
Public MustOverride Sub ProcessRequest(ByVal purchase As Purchase)
End Class
'"ConcreteHandler"
Public Class Director
Inherits Approver
Public Overloads Overrides Sub ProcessRequest(ByVal purchase As Purchase)
If purchase.Amount < 10000 Then
Console.WriteLine("{0} approved request# {1}", Me.[GetType]().Name, purchase.Number)
ElseIf successor IsNot Nothing Then
successor.ProcessRequest(purchase)
End If
End Sub
End Class
'"ConcreteHandler"
Public Class VicePresident
Inherits Approver
Public Overloads Overrides Sub ProcessRequest(ByVal purchase As Purchase)
If purchase.Amount < 25000 Then
Console.WriteLine("{0} approved request# {1}", Me.[GetType]().Name, purchase.Number)
ElseIf successor IsNot Nothing Then
successor.ProcessRequest(purchase)
End If
End Sub
End Class
'"ConcreteHandler"
Public Class President
Inherits Approver
Public Overloads Overrides Sub ProcessRequest(ByVal purchase As Purchase)
If purchase.Amount < 100000 Then
Console.WriteLine("{0} approved request# {1}", Me.[GetType]().Name, purchase.Number)
Else
Console.WriteLine("Request# {0} requires an executive meeting!", purchase.Number)
End If
End Sub
End Class
'Request details
Public Class Purchase
Private m_number As Integer
Private m_amount As Double
Private m_purpose As String
'Constructor
Public Sub New(ByVal number As Integer, ByVal amount As Double, ByVal purpose As String)
Me.m_number = number
Me.m_amount = amount
Me.m_purpose = purpose
End Sub
'Properties
Public Property Amount() As Double
Get
Return m_amount
End Get
Set(ByVal value As Double)
m_amount = value
End Set
End Property
Public Property Purpose() As String
Get
Return m_purpose
End Get
Set(ByVal value As String)
m_purpose = value
End Set
End Property
Public Property Number() As Integer
Get
Return m_number
End Get
Set(ByVal value As Integer)
m_number = value
End Set
End Property
End Class
Chain of Responsibility模式的几个要点:
1、Chain of Responsibility模式的应用场合在于“一个请求可能有多个接受者,但是最后真正的接收者只有一个,只有这时候请求发送者与接收者的耦合才有可能出现“变化脆弱”的症状,职责链的目的就是将二者解耦,从而更好的应对变化。
2、应用了Chain of Responsibility模式后,对象的职责分派将更具灵活性。我们可以在运行时动态添加/修改请求的处理职责。
3、如果请求传递到职责链的末尾仍得不到处理,应该有一个合理的缺省机制,这也是每一个接受对象的责任,而不是发出请求的对象的责任。
我的理解
封装对象责任,支持责任的变化。
参考资料
《C#设计模式(17)-Chain of Responsibility Pattern》 吕震宇
《C#面向对象设计模式纵横谈系列课程(14)》 李建中老师
分类:
Design Pattern
随笔分类 (333)
Cnblogs's
Front End
Oracle's
Software's
- Apache HTTP Server
- CodeSmith Community
- Grapecity(FAQ)
- Mybase
- ClubFarPoint(Forum)
- Beyond Compare
- CrystalReport(FAQ)
- 秀丸
- Software Advice
- Software: Business & Nonprofit | Reviews and Top Software at Capterra
- Capterra
- Business Software Reviews from Software Advice
Copyright © 2025 sekihin
Powered by .NET 9.0 on Kubernetes
Powered by .NET 9.0 on Kubernetes
![]() | 本作品采用 知识共享署名-非商业性使用 2.5 中国大陆许可协议进行许可。 |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通