Android设计模式(一) 工厂模式

简单工厂模式

核心作用就是为了通过工厂类隐藏对象的创建逻辑,避免暴露给调用方

以富士康生产不同类型的Apple Ipad产品为例:

fun main(args: Array) {
    val ipadNeeded = FoxconnFactory().product(PadType.AIR)
    print(ipadNeeded.biometric)
}

interface IPad {
    // 搭载的生物认证识别
    val biometric: String
}

enum class PadType {
    AIR, PRO
}

//
class IpadAir(override val biometric: String = "TouchID") : IPad

class IpadPro(override val biometric: String = "FaceID") : IPad

// 富士康工厂
class FoxconnFactory {
    // 生产线
    fun product(type: PadType): IPad {
        return when (type) {
            PadType.AIR -> IpadAir()
            PadType.PRO -> IpadPro()
        }
    }
}

这是比较典型的Java中简单工厂模式,当然利用kotlin特性可以改造下

object与operator

用object类替代频繁的FoxconnFactory()对象创建,
用operator操作符重载invoke()来替代fun product()方法:

fun main(args: Array) {
    val ipadNeeded = FoxconnFactory(PadType.AIR)
    print(ipadNeeded.biometric)
}

interface IPad {
    // 搭载的生物认证识别
    val biometric: String
}

enum class PadType {
    AIR, PRO
}

//
class IpadAir(override val biometric: String = "TouchID") : IPad

class IpadPro(override val biometric: String = "FaceID") : IPad

// 富士康工厂
object FoxconnFactory {
    operator fun invoke(type: PadType): IPad {
        return when (type) {
            PadType.AIR -> IpadAir()
            PadType.PRO -> IpadPro()
        }
    }
}

companion object

一般我们创建对象,要么使用类公有构造器,要么使用类的静态方法返回实例。所以在业务中,我们通常优先考虑用静态工厂方法来替代构造器,

fun main(args: Array) {
    val ipadNeeded = IPad.FoxconnFactory(PadType.AIR)
    print(ipadNeeded.biometric)
}

interface IPad {
    // 搭载的生物认证识别
    val biometric: String

    //富士康工厂
    companion object FoxconnFactory {
        operator fun invoke(type: PadType): IPad {
            return when (type) {
                PadType.AIR -> IpadAir()
                PadType.PRO -> IpadPro()
            }
        }
    }
}

enum class PadType {
    AIR, PRO
}

//
class IpadAir(override val biometric: String = "Touch ID") : IPad

class IpadPro(override val biometric: String = "Face ID") : IPad

当然 companion object的自定义名称FoxconnFactory是可以去掉的,直接IPad(IPadType.AIR)

扩展函数

kotlin相比较Java设计的强大还在于扩展性,我们利用kotlin伴生对象的特性隐藏了更多的实现细节,如果需要改造其中的逻辑,我们仍然可以利用kotlin中的扩展函数特性扩展companion object,增加一个根据生物认证方式获取IPAD屏幕材质的功能

fun IPad.FoxconnFactory.getScreenMaterial(biometric: String) = when (biometric) {
    "TouchID" -> "LCD"
    "FaceID" -> "OLED"
    else -> "AMOLED"
}

以上便是利用kotlin简单实现了Java中的经典工厂模式,调用方避免直接创建产品对象,而仅仅负责“消费”产品。这是符合开闭原则,对扩展开放、对修改关闭;但是每增加一种类型iPad,都要在工厂类中增加相应的逻辑,这显自然是违背开闭原则的。所以简单工厂模式适用于业务简单的情况下或者具体产品很少增加的情况。而对于复杂的业务环境可能不太适应

在Android中的应用

  • Fragment之前推荐newInstance()创建对象并使用setArguments来传递参数(最新的AndroidX中已经推荐使用FragmentFactory())
  • Service中的onBind(Intent intent)
  • public abstract Object getSystemService (String name) 方法
  • BitmapFactory中利用decodeResourceStream()构造Bitmap对象的过程

工厂方法模式

针对简单工单的补充,与工厂方法模式相比,若增加产品类型前者是修改工厂,后者是创建新工厂

fun main(args: Array) {
    val ipadNeeded = FoxconnFactory(IpadAirFactory()).producePad()
    print(ipadNeeded.biometric)

}

interface IPad {
    // 搭载的生物认证识别
    val biometric: String
}

class IpadAir(override val biometric: String = "TouchID") : IPad
class IpadPro(override val biometric: String = "FaceID") : IPad
class IpadMini(override val biometric: String = "TouchID") : IPad

// 抽象富士康工厂
abstract class FoxconnFactory{
    // 生产不同pad
   abstract fun producePad():Pad
    companion object{
        operator fun invoke(factory: FoxconnFactory): FoxconnFactory{
            return  factory
        }
    }
}
// 生产iPadAir
class IpadAirFactory:FoxconnFactory(){
    override fun producePad() = IpadAir()
}

// 生产iPadPro
class IpadProFactory:FoxconnFactory(){
    override fun producePad()= IpadPro()
}

// 生产iPadMini
class IpadMiniFactory:FoxconnFactory(){
    override fun producePad()= IpadMini()
}

reified关键字

我们利用 operator在抽象工厂类的伴生对象中重载了invoke方法,从而隐藏抽象类的创建过程,但是调用者还是会传入具体的工厂类作为参数构造,利用reified关键字的具体化参数类型特性:

fun main(args: Array) {
    val ipadNeeded = FoxconnFactory().producePad()
    print(ipadNeeded.biometric)
}

interface IPad {
    // 搭载的生物认证识别
    val biometric: String
}

class IpadAir(override val biometric: String = "TouchID") : IPad
class IpadPro(override val biometric: String = "FaceID") : IPad
class IpadMini(override val biometric: String = "TouchID") : IPad

// 抽象富士康工厂
abstract class FoxconnFactory{
    // 对这Apple iPad 一类产品对象声明一个接口
    abstract fun producePad():IPad
    companion object{
       inline operator fun invoke(): FoxconnFactory{
            return  when(T::class){
                IpadAir::class -> IpadAirFactory()
                IpadPro::class -> IpadProFactory()
                IpadMini::class -> IpadMiniFactory()
                else-> throw IllegalArgumentException()
            }
        }
    }
}
// 生产iPadAir
class IpadAirFactory:FoxconnFactory(){
    override fun producePad() = IpadAir()
}

// 生产iPadPro
class IpadProFactory:FoxconnFactory(){
    override fun producePad()= IpadPro()
}

// 生产iPadMini
class IpadMiniFactory:FoxconnFactory(){
    override fun producePad()= IpadMini()
}

//

但是这样在增加产品时候还是会对工厂进行改动,我们利用反射替代工厂类的创建

abstract class FoxconnFactory{
    // 一类Apple iPad 产品对象声明一个接口
//    abstract fun producePad():IPad
    companion object{
       inline operator fun invoke(): IPad?{
           var pad: IPad ? = null
           try {
               pad = T::class.java.newInstance()  as IPad
           }catch (e: Exception){
               e.printStackTrace()
           }
           return  pad
        }
    }
}

当有新的iPad产品时,只要创建并继承抽象产品;新建具体工厂继承抽象工厂;而不用修改任何一个类,工厂方法模式是完全符合开闭原则。但是如果产品种类非常多的时候,比如富士康工厂并不只是生产Apple的产品如果需求加入华为MatePad生产的需求,这时候产品等级又多了一层品牌商,所以要引入抽象工厂

比较典型的就是Java中的集合类List或者set继承自Collection接口,Collection接口继承于Iterable接口。所以List和Set接口也会继承并实现Iterable中的iterator()方法。然后业务中最常用的间接实现类ArrayList和HashSet中的iterator方法就具体构造并返回一个迭代器对象。

抽象工厂模式

工厂方法模式针对单一产品结构,只能抽象一个产品类,具体工厂类也只能生产一个具体产品,而抽象工厂模式是为调用者提供一个接口,可以创建一组相关或者相互依赖的产品对象,也就是有多个抽象产品类,具体工厂类也能生产多个具体产品类

fun main(args: Array) {
    val applePad = AppleFactory().producePad()
    val applePhone = AppleFactory().producePhone()

    val huaweiPad = HuaWeiFactory().producePad()
    val huaweiPhone = HuaWeiFactory().producePhone()

    print(applePad.biometric)
    print(applePhone.cpu)

    print(huaweiPad.biometric)
    print(huaweiPhone.cpu)
}


interface Pad {
    val biometric: String

}

interface Phone {
    // cpu
    val cpu: String
}

abstract class AppleIpad : Pad
abstract class AppleIphone : Phone
class AppleIpadPro(override val biometric: String = "FaceID") : AppleIpad()
class AppleIphone11(override val cpu: String = "A13") : AppleIphone()

abstract class HuaWeiPad : Pad
abstract class HuaWeiMatePhone : Phone


class HuaWeiMatePadPro(override val biometric: String = "TouchID") : HuaWeiPad()
class HuaWeiMate30(override val cpu: String = "Kirin990") : HuaWeiMatePhone()


// 抽象富士康工厂
abstract class FoxconnFactory {
    // 一类pad产品对象声明一个接口
    abstract  fun producePad(): Pad

    // 一类phone产品对象声明一个接口
    abstract fun producePhone(): Phone

}

// 生产Apple产品
class AppleFactory : FoxconnFactory() {
    override fun producePad(): Pad  = AppleIpadPro()
    override fun producePhone(): Phone = AppleIphone11()
}

// 生产HuaWei产品
class HuaWeiFactory : FoxconnFactory() {
    override fun producePad(): Pad = HuaWeiMatePadPro()
    override fun producePhone(): Phone = HuaWeiMate30()

}

这是简单的抽象工厂模式,如果我们需要增加耳机产品只能再新建个产品类再修改抽象工厂,所有的工厂都会被修改,这也是其缺点,利用上述的反射机制优化一下也是可以的

companion object {

        inline fun  producePad(clz: Class): T? {
            var product: T? = null
            try {
                // 利用反射获取空构造创建对象
                product = Class.forName(clz.name).newInstance() as T
            } catch (e: Exception) {
                e.printStackTrace()
            }
            return product
        }

        inline fun  producePhone(clz: Class): T? {
            var product: T? = null
            try {
                // 利用反射获取空构造创建对象
                product = Class.forName(clz.name).newInstance() as T
            } catch (e: Exception) {
                e.printStackTrace()
            }
            return product
        }
    }

Android中的com.android.internal.policy.IPolicy是关于Android窗口,窗口管理,布局加载,以及事件回退Handler这一系列窗口相关产品的抽象工厂。

还有就是MediaPlayerFactory生成不同的MediaPlayer基类,public abstract class MediaPlayerBase implements AutoCloseable

抽象工厂模式不易于拓展新的产品族在一般业务中用的不多。

你可能感兴趣的