在软件开发中,设计模式是解决特定问题的通用解决方案。规格模式(Specification Pattern)是其中一种,它允许定义一个清晰的业务规则,以确定一个对象是否符合特定的标准。本文将通过一个简单的示例来展示规格模式的实现过程。
本文的示例代码基于Eric Evans在其著作《领域驱动设计》中提到的“化学包装”示例。将创建一个简单的规格,用于检查化学桶是否能够装入容器中。
在第一部分中,讨论了规格模式及其使用场景。本文将通过一个工作示例来实现规格模式。
目标是创建一个规格,用于检查容器对象是否满足化学桶的要求。在第三部分中,将探讨如何创建一个通用规格,使其能够适用于任何对象。
化学桶类包含化学名称、数量以及一个容器规格对象,该对象定义了化学桶所需的容器类型。
Public Class Drum
Private _chemical As String
Private _size As Int32
Private _requiredContainer As ContainerSpecification
Public ReadOnly Property Chemical() As String
Get
Return _chemical
End Get
End Property
Public ReadOnly Property Size() As Int32
Get
Return _size
End Get
End Property
Public ReadOnly Property RequiredContainer() As ContainerSpecification
Get
Return _requiredContainer
End Get
End Property
Public Sub New(ByVal chemical As String, ByVal size As Int32, ByVal requiredContainer As ContainerSpecification)
_chemical = chemical
_size = size
_requiredContainer = requiredContainer
End Sub
End Class
容器类用于检查是否能够容纳多个化学桶。容器类包含属性,如特征、容量和已添加的化学桶列表。
Public Class Container
Private _features As ContainerFeature
Private _capacity As Int32
Private _drums As List(Of Drum)
Public ReadOnly Property Features() As ContainerFeature
Get
Return _features
End Get
End Property
Public ReadOnly Property Capacity() As Int32
Get
Return _capacity
End Get
End Property
Public ReadOnly Property Drums() As List(Of Drum)
Get
Return _drums
End Get
End Property
Public Sub AddDrum(ByVal drum As Drum)
_drums.Add(drum)
End Sub
Public Function RemainingSpace() As Int32
Dim usedSpace As Int32 = 0
For Each drum As Drum In _drums
usedSpace += drum.Size
Next
Return _capacity - usedSpace
End Function
Public Function HasSpaceFor(ByVal drum As Drum) As Boolean
Return RemainingSpace() >= drum.Size
End Function
Public Function CanAccommodate(ByVal drum As Drum) As Boolean
Return hasSpaceFor(drum) And drum.RequiredContainer.IsSatisfiedBy(Me)
End Function
Public Function IsSafelyPacked() As Boolean
Dim blnIsSafe As Boolean = True
For Each drum As Drum In _drums
blnIsSafe = blnIsSafe And drum.RequiredContainer.IsSatisfiedBy(Me)
Next
Return blnIsSafe
End Function
Public Sub New(ByVal capacity As Int32, ByVal features As ContainerFeature)
_capacity = capacity
_features = features
_drums = New List(Of Drum)
End Sub
End Class
规格类是一个抽象基类,它定义了一个必须被继承的抽象方法IsSatisfiedBy,该方法接受一个容器对象并返回一个布尔值。
Public MustInherit Class ContainerSpecification
Public MustOverride Function IsSatisfiedBy(ByVal candidate As Container) As Boolean
End Class
需要实现具体的规格类,继承自ContainerSpecification,并检查容器的实际属性。例如,检查容器是否具有装甲特性。
Public Class IsArmored Inherits ContainerSpecification
Public Overrides Function IsSatisfiedBy(ByVal candidate As Container) As Boolean
Return CType((candidate.Features And ContainerFeature.Armored), Boolean)
End Function
End Class
可以在代码中使用IsArmored规格,确保TNT只能存储在装甲容器中。
Dim tntDrum As New Drum("TNT", 3000, New IsArmored)
在第三部分中,将探讨如何将单个规格组合成更复杂的复合语句。目前,可以使用不太优雅的方法来实现。
如果想要创建一个规格,测试容器是否装甲或铅衬,可以按照创建IsArmored或IsVentilated规格的方式进行。
Public Class IsArmoredOrLeadLined Inherits ContainerSpecification
Public Overrides Function IsSatisfiedBy(ByVal candidate As Container) As Boolean
Dim IsArmoredSpec As New IsArmored
Dim IsLeadLinedSpec As New IsLeadLined
Return IsArmoredSpec.IsSatisfiedBy(candidate) Or IsLeadLinedSpec.IsSatisfiedBy(candidate)
End Function
End Class