Android进阶宝典 — 深究23种规划形式(上)中,侧重介绍了创立型规划形式和结构型规划形式,接下来咱们介绍最终一种类型的规划形式 – 行为型形式。

何为行为型,其实在事务开发过程中,咱们会常常碰到一些重复型的使命,咱们不想这些使命都独自去做处理,更想模板化地进行一致处理,这个时分其实就会用到行为型规划形式中的一些形式。

1 模版办法形式

模版办法有点类似于门面规划形式,一般关于一些场景,咱们能够抽象成多个环节,而详细环节的履行,能够交由子类去完结。

例如咱们需求规划一个播映器组件,关于播映器来说,想要播映需求一些前置的流程使命的,例如:

interface IVideoPlayer {
    fun prepare()
    fun setDuration(duration:Long)
    fun setVideoInfo(videoInfo: VideoInfo)
    fun start()
    fun pause()
    fun release()
}

那么详细的完结就能够交给详细完结类完结,例如咱们想要运用Google的ExoPlayer,那么就能够完结一个ExoVideoPlayer类来完结详细的内部逻辑。

class ExoVideoPlayer : IVideoPlayer {
    override fun prepare() {
    }
    override fun setDuration(duration: Long) {
    }
    override fun setVideoInfo(videoInfo: VideoInfo) {
    }
    override fun start() {
    }
    override fun pause() {
    }
    override fun release() {
    }
}

这种规划的思维优势在于,后续假如想要替换播映器的内核,要运用阿里云的播映器,那么就能够再创立一个阿里云播映器的完结类,调用阿里云播映器的API完结内部逻辑,不会违背开闭原则。

class AliVideoPlayer : IVideoPlayer {
    override fun prepare() {
        TODO("Not yet implemented")
    }
    override fun setDuration(duration: Long) {
        TODO("Not yet implemented")
    }
    override fun setVideoInfo(videoInfo: VideoInfo) {
        TODO("Not yet implemented")
    }
    override fun start() {
        TODO("Not yet implemented")
    }
    override fun pause() {
        TODO("Not yet implemented")
    }
    override fun release() {
        TODO("Not yet implemented")
    }
}

2 战略形式

运用战略形式,有点类似于咱们之前说到的静态署理形式,拿上面的例子举例,咱们在运用播映器的时分,能够规划一个战略类,经过事务上层来决议运用哪个播映器的内核。

class VideoPlayerContext:IVideoPlayer {
    private var videoPlayer:IVideoPlayer? = null
    fun setVideoPlayer(videoPlayer: IVideoPlayer){
        this.videoPlayer = videoPlayer
    }
    override fun prepare() {
        videoPlayer?.prepare()
    }
    override fun setDuration(duration: Long) {
        TODO("Not yet implemented")
    }
    override fun setVideoInfo(videoInfo: VideoInfo) {
        TODO("Not yet implemented")
    }
    override fun start() {
        TODO("Not yet implemented")
    }
    override fun pause() {
        TODO("Not yet implemented")
    }
    override fun release() {
        TODO("Not yet implemented")
    }
}

其实这种规划办法许多见,中心仍是在于要完结调用层与完结层的解耦,并且关于事务方来说,只需求挑选某个战略就能够完结灵敏的切换。

3 指令形式

指令规划形式,这个在实践的开发中仍是会常常运用到的,从字面意思上来看,便是经过调用方发起一个指令,然后接收方接收到这个指令之后,就会履行对应的操作,尤其是关于一些同类型的使命,咱们能够聚合分类,做一致的处理。

例如咱们现在有这样一个场景:咱们都用过小度音响,或者小爱同学,他们能够协助咱们完结一些系统的指令,例如开关机、调整屏幕亮度、调节音量等,其实便是事务方发起一个指令之后,系统接收到这个指令后来完结对应的处理。

interface ICommand {
    fun execute(commandName:String)
}

这儿咱们界说了一个指令接口,其间execute办法便是用来做详细的指令履行。

class CommandInvoker {
    private var command:ICommand? = null
    fun setCommand(command:ICommand){
        this.command = command
    }
    fun call(commandName:String){
        command?.execute(commandName)
    }
}

CommandInvoker是调用方的逻辑,用于分发指令给到详细的完结方。

class SystemOsCommand(val receiver: SystemOsCommandReceiver) : ICommand {
    override fun execute(commandName: String) {
        receiver.onReceive(commandName)
    }
}

这儿咱们看到,SystemOsCommand完结了ICommand接口,可是并没有直接去处理指令,而是依赖了SystemOsCommandReceiver,最终交给SystemOsCommandReceiver来处理指令。

class SystemOsCommandReceiver {
    fun onReceive(commandName:String){
    }
}

或许许多同伴们觉得,这不是多此一举吗,在SystemOsCommand中处理逻辑没问题。其实我一开始也是这么觉得,可是关于规划者来说,也是为了解耦,假如不考虑这些问题,那么在调用时就能够直接处理指令,那么逻辑悉数强耦合在一起,不易于扩展。

所以针对这个问题,我对指令形式做了一次修正,既然在调用方调用之前就已经知道指令的类型了,其实就少了一步setCommand办法的调用。

class CommandDispatcher : ICommand {
    private var systemOsCommand: SystemOsCommand? = null
    override fun execute(commandType: CommandType, commandName: String) {
        when (commandType) {
            CommandType.SYSTEM_OS -> {
                if (systemOsCommand == null) {
                    systemOsCommand = SystemOsCommand(SystemOsCommandReceiver())
                }
                systemOsCommand?.execute(commandName)
            }
        }
    }
}
enum class CommandType(desc:String) {
    SYSTEM_OS("系统指令")
}

在运用指令形式的时分,其实会有大量的衍生类产生,因而决议是否运用指令形式,仍是要区分详细的场景来处理。

4 职责链形式

职责链规划形式,一般在多个使命之间存在一定的关联关系,并且下一个使命,往往依赖上一个使命的状况决议是否履行。假如咱们不选用职责链规划形式,那么就会存在一堆 if-else 判断逻辑,

val result = getIdResult()
if (result == STATUS.FAIL){
    //交给下个使命处理
    val nameResult = getNameResult()
    if (nameResult == STATUS.FAIL){
        //交给下一级处理
        val imageResult = getImageResult()
        if (imageResult == STATUS.FAIL){
            //交给下一级处理
        }else{
            Toast.makeText(context,"找到组件了",Toast.LENGTH_SHORT).show()
        }
    }else{
        Toast.makeText(context,"找到组件了",Toast.LENGTH_SHORT).show()
    }
}else{
    //成功
    Toast.makeText(context,"找到组件了",Toast.LENGTH_SHORT).show()
}

这种逻辑彻底耦合在一起,并且在后人接手代码的时分,乃至很难修正里面的逻辑,很有或许一修正就带来其他的问题。

那么职责链规划形式便是用来处理这个问题,咱们就拿上面的例子来说,有做过自动化测试的同伴应该有了解的,一个组件的特点或许包含:id、name,假如在ViewTree中找不到这个组件,假如有组件的截图,能够经过图画算法找到对应的组件位置。

abstract class AbsNodeHandler {
    protected var mHandler: AbsNodeHandler? = null
    fun setNextHandler(handler: AbsNodeHandler) {
        this.mHandler = handler
    }
    abstract fun handleOperation(): STATUS
}

这儿是有一个抽象的职责链处理类,其间每一个使命都能够作为一个职责链元素。

class NodeIdHandler : AbsNodeHandler() {
    override fun handleOperation(): STATUS {
        return if (getIdResult() == STATUS.FAIL) {
            mHandler?.handleOperation() ?: STATUS.FAIL
        } else {
            STATUS.OK
        }
    }
    //这儿只是模拟,假定在这儿处理得到了一个成果,但不一定是STATUS.OK
    private fun getIdResult(): STATUS {
        return STATUS.OK
    }
}
class NodeNameHandler : AbsNodeHandler() {
    override fun handleOperation(): STATUS {
        return if (getNameResult() == STATUS.FAIL) {
            mHandler?.handleOperation() ?: STATUS.FAIL
        } else {
            STATUS.OK
        }
    }
    private fun getNameResult(): STATUS {
        return STATUS.OK
    }
}
class NodeImageHandler : AbsNodeHandler() {
    override fun handleOperation(): STATUS {
        return getImageResult()
    }
    private fun getImageResult(): STATUS {
        return STATUS.OK
    }
}

这儿列了3个使命,其间的逻辑便是,当一个使命履行失利之后,就直接交给下一个职责链节点mHandler来处理使命。

val nodeIdHandler = NodeIdHandler()
val nodeNameHandler = NodeNameHandler()
val modeImageHandler = NodeImageHandler()
nodeIdHandler.setNextHandler(nodeNameHandler)
nodeNameHandler.setNextHandler(modeImageHandler)
val result = nodeIdHandler.handleOperation()
if (result == STATUS.FAIL){
    Toast.makeText(context,"查找组件失利了",Toast.LENGTH_SHORT).show()
}else{
    //成功
    Toast.makeText(context,"找到组件了",Toast.LENGTH_SHORT).show()
}

这样逻辑看起来就非常明晰,并且在某个使命逻辑发生改变时,并不会影响到上面的逻辑调用途,而只需修正每个Handler内部逻辑即可。

5 观察者形式

观察者形式运用的场景就太多了,相信许多同伴们也都知道这个规划形式,最常见的开始便是回调,注册一个onClickListener,就能够拿到点击事情的回调。

其实观察者形式主要有2个对象:观察者和被观察者,关于被观察者来说,会持有一个或者一组观察者,当有音讯订阅宣布时,会告诉一切的观察者。

abstract class AbsObservable {
    private val observers:MutableList<AbsObserver> by lazy { 
        mutableListOf()
    }
    fun register(observer: AbsObserver){
        if (!observers.contains(observer)){
            observers.add(observer)
        }
    }
    fun unregister(observer: AbsObserver){
        if (observers.contains(observer)){
            observers.remove(observer)
        }
    }
    abstract fun notifyObservers()
}

详细的被观察者,能够完结notifyObservers办法,用于告诉一切的观察者。

class RealObservable : AbsObservable() {
    override fun notifyObservers() {
        observers.forEach {
            it.receive()
        }
    }
}

关于观察者来说,只需求被动地接收被观察者传递过来的数据即可。

interface AbsObserver {
    fun receive()
}
class Observer1: AbsObserver {
    override fun receive() {
    }
}
class Observer2 : AbsObserver {
    override fun receive() {
    }
}

作为详细的观察者,Observer1和Observer2,当注册到RealObservable中之后,就能够接收到状况改变的告诉,然后做出相应的处理。

val observer1 = Observer1()
val observer2 = Observer2()
val realObservable = RealObservable()
realObservable.register(observer1)
realObservable.register(observer2)
realObservable.notifyObservers()

由于现在运用观察者与被观察者的组件特别多,或许很少再去写这种结构,可是其间的原理咱们多少仍是要知道一点的。

6 拜访者形式

假如做过ASM插桩的同伴们,应该了解这个规划形式,能够对某个Method进行拜访,然后获取这个办法中的信息,假如感兴趣的同伴,能够看一下 Android字节码插桩全流程解析,可是在实践的开发中这种规划形式根本用不到。

其次还有备忘录形式、解说器形式等,其实也是一种思维,可是实践的开发中并没有太多的用途,其实23种规划形式,并不意味着一切的规划形式在日常开发中都能够用到,而是需求掌握其间的思维,在规划代码时,能够愈加灵敏,带一点“洁癖”。