Android設(shè)計(jì)模式(一) 工廠模式

簡單工廠模式

核心作用就是為了通過工廠類隱藏對象的創(chuàng)建邏輯肛鹏,避免暴露給調(diào)用方

以富士康生產(chǎn)不同類型的Apple Ipad產(chǎn)品為例:

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

interface IPad {
    // 搭載的生物認(rèn)證識別
    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 {
    // 生產(chǎn)線
    fun product(type: PadType): IPad {
        return when (type) {
            PadType.AIR -> IpadAir()
            PadType.PRO -> IpadPro()
        }
    }
}

這是比較典型的Java中簡單工廠模式,當(dāng)然利用kotlin特性可以改造下

object與operator

用object類替代頻繁的FoxconnFactory()對象創(chuàng)建,
用operator操作符重載invoke()來替代fun product()方法:

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

interface IPad {
    // 搭載的生物認(rèn)證識別
    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

一般我們創(chuàng)建對象,要么使用類公有構(gòu)造器肺然,要么使用類的靜態(tài)方法返回實(shí)例。所以在業(yè)務(wù)中腿准,我們通常優(yōu)先考慮用靜態(tài)工廠方法來替代構(gòu)造器际起,

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

interface IPad {
    // 搭載的生物認(rèn)證識別
    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

當(dāng)然 companion object的自定義名稱FoxconnFactory是可以去掉的,直接IPad(IPadType.AIR)

擴(kuò)展函數(shù)

kotlin相比較Java設(shè)計(jì)的強(qiáng)大還在于擴(kuò)展性吐葱,我們利用kotlin伴生對象的特性隱藏了更多的實(shí)現(xiàn)細(xì)節(jié)街望,如果需要改造其中的邏輯,我們?nèi)匀豢梢岳胟otlin中的擴(kuò)展函數(shù)特性擴(kuò)展companion object弟跑,增加一個(gè)根據(jù)生物認(rèn)證方式獲取IPAD屏幕材質(zhì)的功能

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

以上便是利用kotlin簡單實(shí)現(xiàn)了Java中的經(jīng)典工廠模式灾前,調(diào)用方避免直接創(chuàng)建產(chǎn)品對象,而僅僅負(fù)責(zé)“消費(fèi)”產(chǎn)品孟辑。這是符合開閉原則哎甲,對擴(kuò)展開放、對修改關(guān)閉饲嗽;但是每增加一種類型iPad炭玫,都要在工廠類中增加相應(yīng)的邏輯,這顯自然是違背開閉原則的貌虾。所以簡單工廠模式適用于業(yè)務(wù)簡單的情況下或者具體產(chǎn)品很少增加的情況吞加。而對于復(fù)雜的業(yè)務(wù)環(huán)境可能不太適應(yīng)

在Android中的應(yīng)用

  • Fragment之前推薦newInstance()創(chuàng)建對象并使用setArguments來傳遞參數(shù)(最新的AndroidX中已經(jīng)推薦使用FragmentFactory())
  • Service中的onBind(Intent intent)
  • public abstract Object getSystemService (String name) 方法
  • BitmapFactory中利用decodeResourceStream()構(gòu)造Bitmap對象的過程

工廠方法模式

針對簡單工單的補(bǔ)充,與工廠方法模式相比尽狠,若增加產(chǎn)品類型前者是修改工廠衔憨,后者是創(chuàng)建新工廠

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

}

interface IPad {
    // 搭載的生物認(rèn)證識別
    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{
    // 生產(chǎn)不同pad
   abstract fun producePad():Pad
    companion object{
        operator fun invoke(factory: FoxconnFactory): FoxconnFactory{
            return  factory
        }
    }
}
// 生產(chǎn)iPadAir
class IpadAirFactory:FoxconnFactory(){
    override fun producePad() = IpadAir()
}

// 生產(chǎn)iPadPro
class IpadProFactory:FoxconnFactory(){
    override fun producePad()= IpadPro()
}

// 生產(chǎn)iPadMini
class IpadMiniFactory:FoxconnFactory(){
    override fun producePad()= IpadMini()
}

reified關(guān)鍵字

我們利用 operator在抽象工廠類的伴生對象中重載了invoke方法,從而隱藏抽象類的創(chuàng)建過程袄膏,但是調(diào)用者還是會傳入具體的工廠類作為參數(shù)構(gòu)造践图,利用reified關(guān)鍵字的具體化參數(shù)類型特性:

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

interface IPad {
    // 搭載的生物認(rèn)證識別
    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 一類產(chǎn)品對象聲明一個(gè)接口
    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()
            }
        }
    }
}
// 生產(chǎn)iPadAir
class IpadAirFactory:FoxconnFactory(){
    override fun producePad() = IpadAir()
}

// 生產(chǎn)iPadPro
class IpadProFactory:FoxconnFactory(){
    override fun producePad()= IpadPro()
}

// 生產(chǎn)iPadMini
class IpadMiniFactory:FoxconnFactory(){
    override fun producePad()= IpadMini()
}

//


但是這樣在增加產(chǎn)品時(shí)候還是會對工廠進(jìn)行改動,我們利用反射替代工廠類的創(chuàng)建

abstract class FoxconnFactory{
    // 一類Apple iPad 產(chǎn)品對象聲明一個(gè)接口
//    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
        }
    }
}

當(dāng)有新的iPad產(chǎn)品時(shí)沉馆,只要創(chuàng)建并繼承抽象產(chǎn)品平项;新建具體工廠繼承抽象工廠赫舒;而不用修改任何一個(gè)類,工廠方法模式是完全符合開閉原則闽瓢。但是如果產(chǎn)品種類非常多的時(shí)候接癌,比如富士康工廠并不只是生產(chǎn)Apple的產(chǎn)品如果需求加入華為MatePad生產(chǎn)的需求,這時(shí)候產(chǎn)品等級又多了一層品牌商扣讼,所以要引入抽象工廠

比較典型的就是Java中的集合類List或者set繼承自Collection接口缺猛,Collection接口繼承于Iterable接口。所以List和Set接口也會繼承并實(shí)現(xiàn)Iterable中的iterator()方法椭符。然后業(yè)務(wù)中最常用的間接實(shí)現(xiàn)類ArrayList和HashSet中的iterator方法就具體構(gòu)造并返回一個(gè)迭代器對象荔燎。

抽象工廠模式

工廠方法模式針對單一產(chǎn)品結(jié)構(gòu),只能抽象一個(gè)產(chǎn)品類销钝,具體工廠類也只能生產(chǎn)一個(gè)具體產(chǎn)品有咨,而抽象工廠模式是為調(diào)用者提供一個(gè)接口,可以創(chuàng)建一組相關(guān)或者相互依賴的產(chǎn)品對象蒸健,也就是有多個(gè)抽象產(chǎn)品類座享,具體工廠類也能生產(chǎn)多個(gè)具體產(chǎn)品類

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產(chǎn)品對象聲明一個(gè)接口
    abstract  fun producePad(): Pad

    // 一類phone產(chǎn)品對象聲明一個(gè)接口
    abstract fun producePhone(): Phone

}

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

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

}

這是簡單的抽象工廠模式,如果我們需要增加耳機(jī)產(chǎn)品只能再新建個(gè)產(chǎn)品類再修改抽象工廠似忧,所有的工廠都會被修改渣叛,這也是其缺點(diǎn),利用上述的反射機(jī)制優(yōu)化一下也是可以的

companion object {

        inline fun <reified T : Pad> producePad(clz: Class<T>): T? {
            var product: T? = null
            try {
                // 利用反射獲取空構(gòu)造創(chuàng)建對象
                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 {
                // 利用反射獲取空構(gòu)造創(chuàng)建對象
                product = Class.forName(clz.name).newInstance() as T
            } catch (e: Exception) {
                e.printStackTrace()
            }
            return product
        }
    }

Android中的com.android.internal.policy.IPolicy是關(guān)于Android窗口盯捌,窗口管理淳衙,布局加載,以及事件回退Handler這一系列窗口相關(guān)產(chǎn)品的抽象工廠饺著。

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

抽象工廠模式不易于拓展新的產(chǎn)品族在一般業(yè)務(wù)中用的不多箫攀。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市幼衰,隨后出現(xiàn)的幾起案子靴跛,更是在濱河造成了極大的恐慌,老刑警劉巖塑顺,帶你破解...
    沈念sama閱讀 222,729評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異俏险,居然都是意外死亡严拒,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評論 3 399
  • 文/潘曉璐 我一進(jìn)店門竖独,熙熙樓的掌柜王于貴愁眉苦臉地迎上來裤唠,“玉大人,你說我怎么就攤上這事莹痢≈终海” “怎么了墓赴?”我有些...
    開封第一講書人閱讀 169,461評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長航瞭。 經(jīng)常有香客問我诫硕,道長,這世上最難降的妖魔是什么刊侯? 我笑而不...
    開封第一講書人閱讀 60,135評論 1 300
  • 正文 為了忘掉前任章办,我火速辦了婚禮,結(jié)果婚禮上滨彻,老公的妹妹穿的比我還像新娘藕届。我一直安慰自己,他們只是感情好亭饵,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,130評論 6 398
  • 文/花漫 我一把揭開白布休偶。 她就那樣靜靜地躺著,像睡著了一般辜羊。 火紅的嫁衣襯著肌膚如雪踏兜。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,736評論 1 312
  • 那天只冻,我揣著相機(jī)與錄音庇麦,去河邊找鬼。 笑死喜德,一個(gè)胖子當(dāng)著我的面吹牛山橄,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播舍悯,決...
    沈念sama閱讀 41,179評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼航棱,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了饮醇?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,124評論 0 277
  • 序言:老撾萬榮一對情侶失蹤朴艰,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后混移,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,657評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡歌径,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,723評論 3 342
  • 正文 我和宋清朗相戀三年毁嗦,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片狗准。...
    茶點(diǎn)故事閱讀 40,872評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡克锣,死狀恐怖腔长,靈堂內(nèi)的尸體忽然破棺而出袭祟,到底是詐尸還是另有隱情,我是刑警寧澤饼酿,帶...
    沈念sama閱讀 36,533評論 5 351
  • 正文 年R本政府宣布榕酒,位于F島的核電站,受9級特大地震影響想鹰,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜辑舷,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,213評論 3 336
  • 文/蒙蒙 一槽片、第九天 我趴在偏房一處隱蔽的房頂上張望何缓。 院中可真熱鬧还栓,春花似錦碌廓、人聲如沸剩盒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,700評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至跟匆,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間玛臂,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,819評論 1 274
  • 我被黑心中介騙來泰國打工迹冤, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人斑匪。 一個(gè)月前我還...
    沈念sama閱讀 49,304評論 3 379
  • 正文 我出身青樓锋勺,卻偏偏與公主長得像蚀瘸,于是被迫代替她去往敵國和親庶橱。 傳聞我的和親對象是個(gè)殘疾皇子贮勃,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,876評論 2 361

推薦閱讀更多精彩內(nèi)容

  • 工廠模式是創(chuàng)建性模式寂嘉,總共分為三種:簡單工廠模式,工廠方法模式枫绅,抽象工廠模式 什么是工廠模式? 定義一個(gè)用戶創(chuàng)建對...
    雨田Android開發(fā)閱讀 214評論 0 0
  • 簡單工廠模式雖然簡單寓搬,但存在一個(gè)很嚴(yán)重的問題。當(dāng)系統(tǒng)中需要引入新產(chǎn)品時(shí)县耽,由于靜態(tài)工廠方法通過所傳入?yún)?shù)的不同來創(chuàng)建...
    justCode_閱讀 1,190評論 1 9
  • 工廠模式是我們最常用的實(shí)例化對象模式了,是用工廠方法代替new操作的一種模式唾琼。通常我們所說的工廠模式是指工廠方法模...
    zfylin閱讀 1,319評論 0 7
  • 這部電影出其新意的講述了一個(gè)不愿意拿槍上戰(zhàn)場的士兵卻救了75位戰(zhàn)友的故事。 主人公戴斯蒙德小時(shí)候曾經(jīng)歷差...
    與與我無關(guān)閱讀 271評論 0 0
  • 2月17日一大早澎剥,山西農(nóng)科110服務(wù)中心根據(jù)2月16日農(nóng)民吳兆遠(yuǎn)熱線求助的問題,迅速聯(lián)系調(diào)度省農(nóng)科院蔬菜所研究員肴裙、...
    老張139閱讀 257評論 0 0