设计模式就是在某些场景下,针对某类问题的某种通用的解决方案。
使用设计模式可以使得代码可复用、让代码更容易被他人理解、保证代码可靠性。
设计模式总体被分为三类:
- 创建型模式:对象实例化的模式,创建型模式用于解耦对象的实例化过程
- 行为型模式:类和对象如何交互,及划分责任和算法
- 结构型模式:把类或对象结合在一起形成一个更大的结构
本文将讲述行为型模式的使用总结。
行为型模式 观察者模式当对象间存在一对多关系时,可以使用观察者模式。
比如,当一个对象被修改时,则会自动通知依赖它的对象。
代码演示:
步骤1:创建一个抽象的观察者类 Observer
abstract class Observer {
// 观察的对象
protected var subject: Subject? = null
// 当对象更新时,主动触发 update() 方法
abstract fun update()
}
步骤2:创建 Subject 类,作为被观察者
class Subject {
// 持有所有观察者
private val observers: MutableList = 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。
// 观察者 1
class BinaryObserver(subject: Subject) : Observer() {
override fun update() {
println("Binary String: " + Integer.toBinaryString(subject!!.state))
}
init {
this.subject = subject
this.subject!!.attach(this)
}
}
// 观察者 2
class OctalObserver(subject: Subject?) : Observer() {
override fun update() {
println("Octal String: " + Integer.toOctalString(subject!!.state))
}
init {
this.subject = subject
this.subject!!.attach(this)
}
}
// 观察者 3
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策略模式) { 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 类,用于调度策略方法
// 根据外部传进来的 Strategy,调度具体策略方法
class Context(private val strategy: Strategy) {
fun executeStrategy(num1: Int, num2: Int): Int {
return strategy.doOperation(num1, num2)
}
}
步骤四:测试代码
fun main(args: Array状态模式) { 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责任链模式) { 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) {
val loggerChain = chainOfLoggers
// 每次执行 logMessage 方法都会依次从错误日志 -> 文件日志 -> 控制台日志尝试执行 write 方法
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)
}
}
步骤二:创建一个中介者类(聊天室)
// 聊天室,所有 user 都可以调用聊天室的静态方法
object ChatRoom {
fun showMessage(user: User, message: String) {
println(Date().toString() + " [" + user.name + "] : " + message)
}
}
步骤三:测试代码
fun main(args: Array模板模式) { 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) { 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!



