簡單工廠模式
核心作用就是為了通過工廠類隱藏對象的創(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ù)中用的不多箫攀。