Android設計模式(一) 工廠模式

簡單工廠模式

核心做用就是爲了經過工廠類隱藏對象的建立邏輯,避免暴露給調用方java

以富士康生產不一樣類型的Apple Ipad產品爲例:android

fun main(args: Array<String>) {
    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特性能夠改造下git

object與operator

用object類替代頻繁的FoxconnFactory()對象建立, 用operator操做符重載invoke()來替代fun product()方法:bash

fun main(args: Array<String>) {
    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

通常咱們建立對象,要麼使用類公有構造器,要麼使用類的靜態方法返回實例。因此在業務中,咱們一般優先考慮用靜態工廠方法來替代構造器,markdown

fun main(args: Array<String>) {
    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)app

擴展函數

kotlin相比較Java設計的強大還在於擴展性,咱們利用kotlin伴生對象的特性隱藏了更多的實現細節,若是須要改造其中的邏輯,咱們仍然能夠利用kotlin中的擴展函數特性擴展companion object,增長一個根據生物認證方式獲取IPAD屏幕材質的功能ide

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

以上即是利用kotlin簡單實現了Java中的經典工廠模式,調用方避免直接建立產品對象,而僅僅負責「消費」產品。這是符合開閉原則,對擴展開放、對修改關閉;可是每增長一種類型iPad,都要在工廠類中增長相應的邏輯,這顯天然是違背開閉原則的。因此簡單工廠模式適用於業務簡單的狀況下或者具體產品不多增長的狀況。而對於複雜的業務環境可能不太適應函數

在Android中的應用oop

  • Fragment以前推薦newInstance()建立對象並使用setArguments來傳遞參數(最新的AndroidX中已經推薦使用FragmentFactory())
  • Service中的onBind(Intent intent)
  • public abstract Object getSystemService (String name) 方法
  • BitmapFactory中利用decodeResourceStream()構造Bitmap對象的過程

工廠方法模式

針對簡單工單的補充,與工廠方法模式相比,若增長產品類型前者是修改工廠,後者是建立新工廠佈局

fun main(args: Array<String>) {
    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<String>) {
    val ipadNeeded = FoxconnFactory<IpadAir>().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<reified T: IPad> 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<reified T: IPad> 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<String>) {
    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 <reified T : Pad> producePad(clz: Class<T>): T? {
            var product: T? = null
            try {
                // 利用反射獲取空構造建立對象
                product = Class.forName(clz.name).newInstance() as T
            } catch (e: Exception) {
                e.printStackTrace()
            }
            return product
        }

        inline fun <reified T : Phone> producePhone(clz: Class<T>): 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

抽象工廠模式不易於拓展新的產品族在通常業務中用的很少。

相關文章
相關標籤/搜索