持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第25天,点击查看活动详情
前言
在面向对象的开发过程中,其实咱们或多或少的都接触过一些设计模式,可能知道或不知道其对应的名称,也不知道其具体使用场景,今天咱们就来说说几种常见的设计模式,帮助你们在开发过程中,更加得心应手。
正文
命令模式
命令模式(Command)解释:
它可将请求转换为一个包含与请求相关的所有信息的独立对象。 该转换让你能根据不同的请求将方法参数化、 延迟请求执行或将其放入队列中, 且能实现可撤销操作。
这里的关键就是包装请求对象、放入/移除队列、可撤销
命令模式和正常请求的区别就在,正常模式下,行为请求者与行为实现者通常是一种紧耦合的关系,但在特殊情况下,比如需要对行为进行记录、撤销或重做、事务等处理时,这种无法抵御变化的紧耦合的设计就不太合适。所以这时,命令模式就比较适合。
举个生活中的例子:
比如我去餐厅点吃的,点餐员将我点的东西写在纸条上,然后贴在后厨的窗户上,厨师会根据贴纸的顺序去做菜,当我不想要了的时候,点餐员就可以去把贴纸撕下来,当厨师没看见我的那张贴纸时,就不会做我点的菜。
下面咱们再通过一个例子来说明
定义一个命令协议(Command
),里面包括两个函数execute
(执行)
import XCTest
protocol Command {
func execute()
}
复制代码
写一个简单的命令,继承自命令协议,可以实现简单的操作
class SimpleCommand: Command {
private var payload: String
init(_ payload: String) {
self.payload = payload
}
func execute() {
print("SimpleCommand: See, I can do simple things like printing (" + payload + ")")
}
}
复制代码
再看一个复杂点的命令
定义一个 Receiver 类,它包含一些重要的业务逻辑。 他们知道如何执行与执行请求相关的各种操作。 事实上,任何类都可以作为接收者。
class Receiver {
func doSomething(_ a: String) {
print("Receiver: Working on (" + a + ")\n")
}
func doSomethingElse(_ b: String) {
print("Receiver: Also working on (" + b + ")\n")
}
}
复制代码
然后定义一个复杂命令(ComplexCommand
),里面有个Receiver
类的属性,当实例化ComplexCommand
命令后,执行execute
方法,就可以操作Receiver
类里的方法
/// 但是,某些命令可以将更复杂的操作委托给其他对象,称为“接收器”。
class ComplexCommand: Command {
private var receiver: Receiver
/// Context data, required for launching the receiver's methods.
private var a: String
private var b: String
/// Complex commands can accept one or several receiver objects along with
/// any context data via the constructor.
init(_ receiver: Receiver, _ a: String, _ b: String) {
self.receiver = receiver
self.a = a
self.b = b
}
/// Commands can delegate to any methods of a receiver.
func execute() {
print("ComplexCommand: Complex stuff should be done by a receiver object.\n")
receiver.doSomething(a)
receiver.doSomethingElse(b)
}
}
复制代码
定义一个调用者(Invoker
)类 Invoker 与一个或多个命令相关联。 它向命令发送请求。
class Invoker {
private var onStart: Command?
private var onFinish: Command?
/// Initialize commands.
func setOnStart(_ command: Command) {
onStart = command
}
func setOnFinish(_ command: Command) {
onFinish = command
}
/// Invoker 不依赖于具体的命令或接收器类。 调用者通过执行命令间接将请求传递给接收者。
func doSomethingImportant() {
print("Invoker: Does anybody want something done before I begin?")
onStart?.execute()
print("Invoker: ...doing something really important...")
print("Invoker: Does anybody want something done after I finish?")
onFinish?.execute()
}
}
复制代码
最后看看 执行和结果
class CommandConceptual: XCTestCase {
func test() {
/// The client code can parameterize an invoker with any commands.
let invoker = Invoker()
invoker.setOnStart(SimpleCommand("Say Hi!"))
let receiver = Receiver()
invoker.setOnFinish(ComplexCommand(receiver, "Send email", "Save report"))
invoker.doSomethingImportant()
}
}
复制代码
Invoker: Does anybody want something done before I begin?
SimpleCommand: See, I can do simple things like printing (Say Hi!)
Invoker: ...doing something really important...
Invoker: Does anybody want something done after I finish?
ComplexCommand: Complex stuff should be done by a receiver object.
Receiver: Working on (Send email)
Receiver: Also working on (Save report)
复制代码
结语
命令模式适用场景
- 如果你需要通过操作来参数化对象, 可使用命令模式。
- 如果你想要将操作放入队列中、 操作的执行或者远程执行操作, 可使用命令模式。
命令模式优缺点
优点
- 单一职责原则。 你可以解耦触发和执行操作的类。
- 开闭原则。 你可以在不修改已有客户端代码的情况下在程序中创建新的命令。
- 你可以实现撤销和恢复功能。
- 你可以实现操作的延迟执行。
缺点
- 代码可能会变得更加复杂, 因为你在发送者和接收者之间增加了一个全新的层次。
扩展阅读 下面还有其他模式