结构图
角色
- 环境(Context)角色:持有一个Strategy类的引用。
- 抽象策略者(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略者对象所需的接口。
- 具体策略者(ConcreteStrategy)角色:封装了相关的算法和行为。通过对抽象策略者的多态派生,支持算法的变化。
动机
在软件构建过程中,某些对象使用的算法可能多种多样,经常改变,如果将这些算法都编码到对象中,将会使对象变得异常复杂;而且有时候支持不使用的算法也是一个性能负担。
如何在运行时根据需要透明地更改对象的算法?将算法与对象本身解耦,从而避免上述问题?
意图
定义一系列算法,把它们一个一个封装起来,并且使它们可互相转换。该模式使得算法可独立于使用它的客户而变化。
示意性代码
示意性代码
'Strategy pattern -- Structural example
'MainApp test application
Module MainApp
Public Sub Main()
Dim context As Context
'Three contexts following different strategies
context = New Context(New ConcreteStrategyA())
context.ContextInterface()
context = New Context(New ConcreteStrategyB())
context.ContextInterface()
context = New Context(New ConcreteStrategyC())
context.ContextInterface()
'Wait for user
Console.Read()
End Sub
End Module
'"Strategy"
Public MustInherit Class Strategy
Public MustOverride Sub AlorithmInterface()
End Class
'"ConcreteStrategyA"
Public Class ConcreteStrategyA
Inherits Strategy
Public Overrides Sub AlorithmInterface()
Console.WriteLine( _
"Called ConcreteStrategyA.AlgorithmInterface()")
End Sub
End Class
'"ConcreteStrategyB"
Public Class ConcreteStrategyB
Inherits Strategy
Public Overrides Sub AlorithmInterface()
Console.WriteLine( _
"Called ConcreteStrategyB.AlgorithmInterface()")
End Sub
End Class
'"ConcreteStrategyC"
Public Class ConcreteStrategyC
Inherits Strategy
Public Overrides Sub AlorithmInterface()
Console.WriteLine( _
"Called ConcreteStrategyC.AlgorithmInterface()")
End Sub
End Class
'"Context"
Public Class Context
'Fields
Private strategy As Strategy
'Constructors
Public Sub New(ByVal strategy As Strategy)
Me.strategy = strategy
End Sub
Public Sub ContextInterface()
strategy.AlorithmInterface()
End Sub
End Class
一个实例
下面的例子利用策略模式在排序对象中封装了不同的排序算法,这样以便允许客户端动态的替换排序策略(包括Quicksort、Shellsort和Mergesort)。
实例代码
'MainApp test application
Module MainApp
Public Sub Main()
'Two contexts following different strategies
Dim studentRecords As New SortedList
studentRecords.Add("Samual")
studentRecords.Add("Jimmy")
studentRecords.Add("Sandra")
studentRecords.Add("Vivek")
studentRecords.Add("Anna")
'Three contexts following different strategies
studentRecords.SetSortStrategy(New QuickSort())
studentRecords.Sort()
studentRecords.SetSortStrategy(New ShellSort())
studentRecords.Sort()
studentRecords.SetSortStrategy(New MergeSort())
studentRecords.Sort()
'Wait for user
Console.Read()
End Sub
End Module
'"Strategy"
Public MustInherit Class SortStrategy
Public MustOverride Sub Sort(ByVal list As ArrayList)
End Class
'"ConcreteStrategy"
Public Class QuickSort
Inherits SortStrategy
Public Overrides Sub Sort(ByVal list As ArrayList)
list.Sort() 'Default is QuickSort
Console.WriteLine( _
"QuickSorted list ")
End Sub
End Class
'"ConcreteStrategy"
Public Class ShellSort
Inherits SortStrategy
Public Overrides Sub Sort(ByVal list As ArrayList)
'list.ShellSort(); not-implemented
Console.WriteLine( _
"ShellSorted list ")
End Sub
End Class
'"ConcreteStrategyC"
Public Class MergeSort
Inherits SortStrategy
Public Overrides Sub Sort(ByVal list As ArrayList)
'list.MergeSort(); not-implemented
Console.WriteLine( _
"MergeSorted list ")
End Sub
End Class
'"Context"
Public Class SortedList
'Fields
Private sortstrategy As SortStrategy
Private list As New ArrayList()
'Constructors
Public Sub SetSortStrategy(ByVal sortstrategy As SortStrategy)
Me.sortstrategy = sortstrategy
End Sub
Public Sub Add(ByVal name As String)
list.Add(name)
End Sub
Public Sub Sort()
sortstrategy.Sort(list)
For Each name As String In list
Console.WriteLine(" " & name)
Next
Console.WriteLine()
End Sub
End Class
Strategy Pattern模式的几个要点:
1、Strategy及其子类为组件提供了一系列可重用的算法,从而可以使得类型在运行时方便地根据需要在各个算法之间进行切换。所谓封装算法,支持算法的变化。
2、Strategy模式提供了用条件判断语句以外的另一种选择,消除条件判断语句,就是在解耦合。含有许多条件判断语句的代码通常都需Strategy模式。
3、与State类似,如果Strategy对象没有实例变量,那么各个上下文可以共享同一个Strategy对象,从而节省对象开销。
我的理解
封装算法,支持算法的变化。
参考资料
《C#面向对象设计模式纵横谈系列课程(23)》 李建中老师