在本博客中,我们将简短介绍如何在Kotlin中实现策略和状态模式。由于这两种模式在软件行业中都是众所周知的,因此我们不会讨论它们的优缺点,因为这种情况已经被做过数百次了。本示例将直接使用教科书《设计模式 :可重用面向对象软件的元素》中的示例。鼓励阅读这本书,因为它为软件行业带来了很多有价值的内容。
策略模式与状态模式密切相关。因此,我们将在同一篇博客一起介绍它们。
1、策略模式
当今软件最常见的模式之一是所谓的策略模式。它被称为"政策模式"。由于其简单性,大多数开发人员都很容易理解。此外,它还有助于实现符合面向对象设计的SOLID原则的可扩展软件解决方案。
定义一系列算法,封装每个算法,并使它们可以互换。策略使算法能够独立于使用它的客户端而变化。
GoF,设计模式
1.1、示例说明
当客户对同一问题使用不同的算法时,可以使用此模式。经常发生的问题之一是将文本流(例如大字符串)分解为较小的字符串。我们称之为换行算法。根据上下文,人们可能会使用不同的算法。使用代码的客户不应该依赖于具体的实现。
我们将每个算法封装到一个单独的类中(称为策略)。这些类中的每一个都必须实现某个接口,该接口将由客户端(直接或间接)使用。
在我们的例子中,我们将处理三种不同的算法SimpleCompositor
、TeXCompositor
和ArrayCompositor
。客户端类(Composition)将使用抽象类Compositor
。下面的UML图说明了类设置。
1.2、Kotlin中的实现
为了在Kotlin中实现上述示例,我们将使用抽象接口Compositor
。所有用作算法的类都必须实现此接口。
kotlin
interface Compositor {
fun compose()
}
class SimppleCompositor: Compositor {
override fun compose() {
println("SimpleCompositor::compose")
}
}
class TeXCompositor: Compositor {
override fun compose() {
println("TeXCompositor::compose")
}
}
class ArrayCompositor: Compositor {
override fun compose() {
println("ArrayCompositor::compose")
}
}
class Composition(private var compositor: Compositor) {
fun traverse() {
compositor.compose()
}
fun repair() {
compositor.compose()
}
}
fun main() {
val teXCompositor = TeXCompositor()
val composition = Composition(texCompositor)
composition.repair()
}
2、状态模式
这种模式与策略模式密切相关。我们希望能够在对象的状态发生变化时改变其行为。这种行为变化对于将使用该类的客户端来说应该是透明的。
允许对象在其内部状态发生变化时改变其行为。该对象似乎会更改其类。
GoF------设计模式
2.1、示例说明
考虑一个TCPConnection
表示TCP网络连接的类。它可以有多种状态,例如Established
、Listen
和Closed
。根据不同的状态,它的工作(行为)会有所不同。我们将把每个状态(及其功能)封装在一个类中。所有类(状态)都必须实现抽象类提供的接口TCPState
。下面的UML图说明了类设置。
请注意,与原始设计相反,我们TCPConnection
还实现了TCPState
。
2.2、Kotlin中的实现
该模式的实现方式与前面的示例类似。我们将使用提供函数声明的抽象接口。所有状态都将实现该接口。该类TCPConnection
有一个状态成员,并将所有函数调用直接委托给其状态。
请注意,我们不能使用Kotlin内置的委托模式。如教程所述,一旦将委托分配得对象,当前就无法更改委托。换句话说,我们无法使用此模式更改状态。这意味着我们必须手动实现该接口。
kotlin
interface TCPState {
fun open()
fun clone()
fun acknowledge()
}
class TCPEstablished: TCPState {
override fun open() {
println("TCPEstablished::open")
}
override fun close() {
println("TCPEstablished::close")
}
override fun acknowledge() {
println("TCPEstablished::acknowledge")
}
}
class TCPListen: TCPState {
override fun open() {
println("TCPListen::open")
}
override fun close() {
println("TCPListen::close")
}
override fun acknowledge() {
println("TCPListen::acknowledge")
}
}
class TCPClosed: TCPState {
override fun open() {
println("TCPClosed::open")
}
override fun close() {
println("TCPClosed::close")
}
override fu acknowledge() {
println("TCPClosed::acknowledge")
}
}
class TCPConnection: TCPState {
private var state: TCPState = TCPListen()
override fun open() {
state.open()
}
override fun close() {
state.close()
}
override fun acknowledge() {
state.acknowledge()
}
fun changeState() {
// other state
}
}
fun main() {
val connection = TCPConnection()
connection.open()
connection.changeState()
}