美文网首页
给人看的Kotlin设计模式——抽象工厂

给人看的Kotlin设计模式——抽象工厂

作者: 珞泽珈群 | 来源:发表于2020-04-21 16:39 被阅读0次

    给人看的Kotlin设计模式目录

    概念

    抽象工厂模式相对正式的定义:

    The abstract factory pattern provides a way to encapsulate a group of individual factories that have a common theme without specifying their concrete classes. (Wikipedia)

    这个定义看上去也不咋正式啊,的确,抽象工厂模式实际上只是工厂方法模式的扩展,将其归入工厂方法模式也并无不妥。但是,既然它被单独列出来了,那自然还是有它不同之处的。以上定义中的关键字是 a group of,也就是“一组”,一组什么呢?一组相关联的工厂方法,一组工厂方法就会构造出一组产品,称之为产品族。工厂方法模式强调的是一个工厂方法与产品,抽象工厂模式强调的是一组工厂方法与产品族。

    产品:举个例子,手机是个产品,用编程的语言讲就是手机是个接口,其实现类可能包含小米手机、苹果手机等。我们定义一个工厂方法要求返回一部手机,这是工厂方法模式。

    产品族:现在我们觉得手机这个接口抽象层次太高了,要把它拆分成抽象层次更低的接口,于是我们定义了CPU接口、内存接口、摄像头接口等等,这就是个产品族了。我们定义一组工厂方法要求分别返回以上各个接口,这是抽象工厂模式。

    核心思想:对象创建与对象使用分离。

    那么使用抽象工厂模式的目的是什么呢?其实跟工厂方法模式是一样的,最主要的目的就是分离对象创建和使用,让使用者可以面向接口编程,而无须理会具体对象是如何创建的以及对象的具体类型是什么。

    示例

    从工厂方法模式到抽象工厂模式只是从产品到产品族的扩展,现实中我们需要定义一个产品族的情况并不多,所以抽象工厂模式实际上的应用也不多。我们来看看MvRx中抽象工厂模式的一个应用。

    这里有必要介绍一下背景知识。ViewModel承载着我们所有的业务逻辑,MvRx对ViewModel进行了扩展,要求ViewModel创建时必须提供一个State,这个State实际上就是一个Kotlin data class,它包含了页面显示所有的数据。MvRx的核心思想就是改变这个State进而驱动页面更新,所以MvRx要求每个ViewModel创建时必须提供一个State,这个初始State就代表了页面的初始状态。用“抽象工厂模式”的话说就是ViewModel和State构成了一个产品族。

    来看一下MvRx对于抽象工厂模式实际的应用:

    //抽象工厂
    interface MvRxViewModelFactory<VM : BaseMvRxViewModel<S>, S : MvRxState> {
    
        //工厂方法1,构造ViewModel
        //这里的参数state就是 initialState 初始化好的state
        @Suppress("Detekt.FunctionOnlyReturningConstant")
        fun create(viewModelContext: ViewModelContext, state: S): VM? = null
    
        //工厂方法2,初始化State
        @Suppress("Detekt.FunctionOnlyReturningConstant")
        fun initialState(viewModelContext: ViewModelContext): S? = null
    }
    

    该抽象工厂就包含了两个工厂方法,只是每个工厂方法都默认返回null。在MvRx中,实现MvRxViewModelFactory是个可选项,一般都是为了依赖注入才会去实现MvRxViewModelFactory,并且MvRx要求必须在使用ViewModel的伴生对象来实现MvRxViewModelFactory:

    class MyViewModel(initialState: MyState, dataStore: DataStore) : BaseMvRxViewModel(initialState) {
    
        //伴生对象实现 MvRxViewModelFactory接口
        companion object : MvRxViewModelFactory<MyViewModel, MyState> {
    
            override fun create(viewModelContext: ViewModelContext, state: MyState): MyViewModel {
                val dataStore = if (viewModelContext is FragmentViewModelContext) {
                  // If the ViewModel has a fragment scope it will be a FragmentViewModelContext, and you can access the fragment.
                  viewModelContext.fragment.inject()
                } else {
                  // The activity owner will be available for both fragment and activity view models.
                  viewModelContext.activity.inject()
                }
                //具体实现并不是很重要,总之就是让我们有机会自己构造 MyViewModel,注入 dataStore
                return MyViewModel(state, dataStore)
            }
            
            override fun initialState(viewModelContext: ViewModelContext): MyState? {
                
                // The owner is available too, if your state needs a value stored in a DI component, for example.
                val foo = viewModelContext.activity.inject()
                //我们自己构造 MyState
                return MyState(foo)
            }
    
        } 
    }
    

    如前所述,实现MvRxViewModelFactory是可选项,并且MvRxViewModelFactory中工厂方法都有默认返回值null,所以即使实现MvRxViewModelFactory,也不是两个工厂方法都必须自己实现,如果我们不实现哪个工厂方法,或者连MvRxViewModelFactory接口都不去实现,那么最后MyState和MyViewModel都会通过反射构造出来。

    以上这个例子并不是严格意义上的抽象工厂模式,首先State和ViewModel并不是严格的产品族,而是依赖关系;其次,抽象工厂模式强调的是面向产品族接口编程,这里其实也没有,只是为了构造出ViewModel。这个例子只是长着抽象工厂模式样子的简单工厂模式,大家理解就好,不必太深究其中的细节。如同目录中提到的那样,设计模式是为了解决问题的,而不是发现问题的,关键是理解各个设计模式的思想,然后灵活应用。给模式起名字是为了方便交流,而不是限制我们的思想。

    结构

    抽象工厂模式的经典结构:

    其实跟工厂方法模式是一样的,只是产品从单一的产品Product变成了产品族ProductA和ProductB。

    相关文章

      网友评论

          本文标题:给人看的Kotlin设计模式——抽象工厂

          本文链接:https://www.haomeiwen.com/subject/nlxpihtx.html