【设计模式】之 行为型模式
设计模式就是在某些场景下,针对某类问题的某种通用的解决方案。
使用设计模式可以使得代码可复用、让代码更容易被他人理解、保证代码可靠性。
设计模式总体被分为三类:
- 创建型模式:对象实例化的模式,创建型模式用于解耦对象的实例化过程
- 行为型模式:类和对象如何交互,及划分责任和算法
- 结构型模式:把类或对象结合在一起形成一个更大的结构
本文将讲述行为型模式的使用总结。
行为型模式
观察者模式
当对象间存在一对多关系时,可以使用观察者模式。
比如,当一个对象被修改时,则会自动通知依赖它的对象。
代码演示:
步骤1:创建一个抽象的观察者类 Observer
abstract class Observer {
protected var subject: Subject? = null
abstract fun update()
}
步骤2:创建 Subject 类,作为被观察者
class Subject {
private val observers: MutableList<Observer> = ArrayList()
var state = 0
set(state) {
field = state
notifyAllObservers()
}
fun attach(observer: Observer) {
observers.add(observer)
}
private fun notifyAllObservers() {
observers.forEach {
it.update()
}
}
}
步骤3:创建 3个 实体观察者类,继承 Observer,观察对象是 Subject。
class BinaryObserver(subject: Subject) : Observer() {
override fun update() {
println("Binary String: " + Integer.toBinaryString(subject!!.state))
}
init {
this.subject = subject
this.subject!!.attach(this)
}
}
class OctalObserver(subject: Subject?) : Observer() {
override fun update() {
println("Octal String: " + Integer.toOctalString(subject!!.state))
}
init {
this.subject = subject
this.subject!!.attach(this)
}
}
class HexaObserver(subject: Subject?) : Observer() {
override fun update() {
println("Hex String: " + Integer.toHexString(subject!!.state).toUpperCase())
}
init {
this.subject = subject
this.subject!!.attach(this)
}
}
步骤4:测试代码
fun main(args: Array<String>) {
val subject = Subject()
HexaObserver(subject)
OctalObserver(subject)
BinaryObserver(subject)
println("First state change: 15")
subject.state = 15
println("Second state change: 10")
subject.state = 10
}
First state change: 15
Hex String: F
Octal String: 17
Binary String: 1111
Second state change: 10
Hex String: A
Octal String: 12
Binary String: 1010
策略模式
一个类的行为或其算法需要在运行时更改,可以使用在策略模式
我们可以定义一系列的算法,把它们一个个封装起来,,并且使它们可相互替换。
优点:
缺点:
- 策略类会增多(如果一个系统的策略多于四个,就需要考虑使用混合模式)
- 所有策略类都需要对外暴露
代码演示:
步骤一:创建一个 Strategy 接口
interface Strategy {
fun doOperation(num1: Int, num2: Int): Int
}
步骤二:创建实现接口的实体类
class OperationAdd : Strategy {
override fun doOperation(num1: Int, num2: Int): Int {
return num1 + num2
}
}
class OperationSubtract : Strategy {
override fun doOperation(num1: Int, num2: Int): Int {
return num1 - num2
}
}
class OperationMultiply : Strategy {
override fun doOperation(num1: Int, num2: Int): Int {
return num1 * num2
}
}
步骤三:创建 Context 类,用于调度策略方法
class Context(private val strategy: Strategy) {
fun executeStrategy(num1: Int, num2: Int): Int {
return strategy.doOperation(num1, num2)
}
}
步骤四:测试代码
fun main(args: Array<String>) {
var context = Context(OperationAdd())
System.out.println("10 + 5 = " + context.executeStrategy(10, 5))
context = Context(OperationSubtract())
System.out.println("10 - 5 = " + context.executeStrategy(10, 5))
context = Context(OperationMultiply())
System.out.println("10 * 5 = " + context.executeStrategy(10, 5))
}
10 + 5 = 15
10 - 5 = 5
10 * 5 = 50
状态模式
当对象的行为依赖于自己的状态(属性),并且可以根据自己的状态改变,从而改变自己的相关行为,可以使用状态模式。
例如,我们打篮球的时候,可以有正常状态、不正常状态和超常状态。
代码演示:
步骤一:创建一个 Context 类,用于保存状态
class Context {
var state: State? = null
}
步骤二:创建一个 State 接口
interface State {
fun doAction(context: Context)
}
步骤三:创建两个实现了 State 接口的实体 状态类
class StartState : State {
override fun doAction(context: Context) {
println("Player is in start state")
context.state = this
}
override fun toString(): String {
return "Start State"
}
}
class StopState : State {
override fun doAction(context: Context) {
println("Player is in stop state")
context.state = this
}
override fun toString(): String {
return "Stop State"
}
}
步骤四:测试代码
fun main(args: Array<String>) {
val context = Context()
val startState = StartState()
startState.doAction(context)
println(context.state.toString())
val stopState = StopState()
stopState.doAction(context)
println(context.state.toString())
}
Player is in start state
Start State
Player is in stop state
Stop State
责任链模式
责任链模式为请求创建了一个接收者对象的链。在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。
责任链模式对请求的 发送者 和 接收者 进行了解耦。让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。
代码演示:
步骤一:创建抽象的日志记录器类
abstract class AbstractLogger {
var level = 0
var nextLogger: AbstractLogger? = null
fun logMessage(level: Int, message: String?) {
if (this.level <= level) {
write(message)
}
if (nextLogger != null) {
nextLogger!!.logMessage(level, message)
}
}
protected abstract fun write(message: String?)
companion object {
var INFO = 1
var DEBUG = 2
var ERROR = 3
}
}
步骤二:创建扩展了抽象记录器类的实体类
class ConsoleLogger(level: Int) : AbstractLogger() {
override fun write(message: String?) {
println("Standard Console::Logger: $message")
}
init {
this.level = level
}
}
class ErrorLogger(level: Int) : AbstractLogger() {
override fun write(message: String?) {
println("Error Console::Logger: $message")
}
init {
this.level = level
}
}
class FileLogger(level: Int) : AbstractLogger() {
override fun write(message: String?) {
println("File::Logger: $message")
}
init {
this.level = level
}
}
步骤三:测试代码
object ChainPatternDemo {
private val chainOfLoggers: AbstractLogger
get() {
val errorLogger: AbstractLogger = ErrorLogger(AbstractLogger.ERROR)
val fileLogger: AbstractLogger = FileLogger(AbstractLogger.DEBUG)
val consoleLogger: AbstractLogger = ConsoleLogger(AbstractLogger.INFO)
errorLogger.nextLogger = fileLogger
fileLogger.nextLogger = consoleLogger
return errorLogger
}
@JvmStatic
fun main(args: Array<String>) {
val loggerChain = chainOfLoggers
loggerChain.logMessage(AbstractLogger.INFO, "This is an information.")
loggerChain.logMessage(
AbstractLogger.DEBUG,
"This is a debug level information."
)
loggerChain.logMessage(
AbstractLogger.ERROR,
"This is an error information."
)
}
}
Standard Console::Logger: This is an information.
File::Logger: This is a debug level information.
Standard Console::Logger: This is a debug level information.
Error Console::Logger: This is an error information.
File::Logger: This is an error information.
Standard Console::Logger: This is an error information.
中介者模式
中介者模式是用来降低多个对象和类之间的通信复杂性。
中介者模式提供了一个中介类,该类通常处理不同类之间的通信,并支持松耦合,使代码易于维护。
例如,在 MVC 框架中,其中 C(控制器)就是 M(模型)和 V(视图)的中介者。
代码演示:
我们通过聊天室实例来演示中介者模式。
实例中,多个用户可以向聊天室发送消息,聊天室向所有的用户显示消息。
步骤一:创建一个 User 类
class User(var name: String) {
fun sendMessage(message: String) {
ChatRoom.showMessage(this, message)
}
}
步骤二:创建一个中介者类(聊天室)
object ChatRoom {
fun showMessage(user: User, message: String) {
println(Date().toString() + " [" + user.name + "] : " + message)
}
}
步骤三:测试代码
fun main(args: Array<String>) {
val robert = User("Robert")
val john = User("John")
robert.sendMessage("Hi! John!")
john.sendMessage("Hello! Robert!")
}
Thu Jan 31 16:05:46 IST 2013 [Robert] : Hi! John!
Thu Jan 31 16:05:46 IST 2013 [John] : Hello! Robert!
模板模式
在模板模式中,一个抽象类公开定义了执行它的方法的模板。
它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
优点:
- 封装不变部分,扩展可变部分
- 提取公共代码,便于维护
- 行为由父类控制,子类实现
缺点:
- 每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大
**注意:**为防止恶意操作,一般模板方法都加上 final 关键字,或者模板方法不允许修改
代码演示:
步骤一:定义一个抽象的游戏模板类,且模板方法无法被重写
abstract class Game {
abstract fun initialize()
abstract fun startPlay()
abstract fun endPlay()
fun play() {
initialize()
startPlay()
endPlay()
}
}
步骤二:创建扩展了上述类的实体类
class Cricket : Game() {
override fun initialize() {
println("Cricket Game Initialized! Start playing.")
}
override fun startPlay() {
println("Cricket Game Started. Enjoy the game!")
}
override fun endPlay() {
println("Cricket Game Finished!")
}
}
class Football : Game() {
override fun initialize() {
println("Football Game Initialized! Start playing.")
}
override fun startPlay() {
println("Football Game Started. Enjoy the game!")
}
override fun endPlay() {
println("Football Game Finished!")
}
}
步骤三:测试代码
fun main(args: Array<String>) {
val game1 = Cricket()
game1.play()
val game2 = Football()
game2.play()
}
Cricket Game Initialized! Start playing.
Cricket Game Started. Enjoy the game!
Cricket Game Finished!
Football Game Initialized! Start playing.
Football Game Started. Enjoy the game!
Football Game Finished!
|