![](/img/trans.png)
[英]Swift opposite to “required”, or factory design pattern with required init methods in superclass
[英]Swift: Factory Pattern, Subclass methods are not visible
我是Swift編程的新手,在構造Factory設計模式時遇到了障礙。 下面是我的代碼:
protocol IInterface {
func InterfaceMethod() -> Void
}
public class SubClass: IInterface {
init() {}
func InterfaceMethod() { }
public func SubClassMethod() { }
}
public class Factory() {
class func createFactory() -> IInterface {
return SubClass()
}
}
最后,我正在嘗試像下面這樣訪問它
let mgr = Factory.createFactory()
//calling Interface Method
mgr.InterfaceMethod() -- This works, when i keep a dot (mgr.) it shows the method name
//calling subclass method
mgr.SubClassMethod() -- This doesn't work, when i keep a dot (mgr.) it doesnt even show the subclass method name
即使我使用mgr.SubClassMethod
,它mgr.SubClassMethod
引發錯誤提示
IInterface類型的值沒有成員SubClassMethod
我相信盡管通過工廠返回了SubClass對象,但我只能使用協議方法
我瀏覽並看到的所有示例僅顯示了如何使用協議指定的方法,但是我沒有看到一個示例,該示例顯示了如何使用除協議方法之外的子類自己的方法
您錯過了工廠模式的要點。 Factory模式的想法是提供具有特定返回類型的方法,並提供具有該類型或從該類型繼承(如果是class
類型)或符合該類型(如果是protocol
)的實例。
protocol Animal {
func voice() -> String
}
class Dog: Animal {
func voice() -> String {
return "bark"
}
func sit() {
}
}
class Cat: Animal {
func voice() -> String {
return "meow"
}
}
class AnimalFactory {
func getAnimal() -> Animal {
return Dog()
}
}
調用Factory方法的客戶端代碼不應推測其返回值,並嘗試將其強制轉換為具體類。 這完全破壞了使用Factory模式的意義。
如您在上面的示例中看到的, AnimalFactory.getAnimal()
返回符合Animal
協議的某種類型的實例。 調用此方法的代碼不知道也不應該知道該實例的特定類型。
如果調用Factory方法的代碼期望返回的實例具有Dog
類型或從該類型繼承,則您應該創建並使用單獨的DogFactory
:
class EvilDog: Dog {
override func voice() -> String {
return "bark-bark"
}
}
class DogFactory {
func getDog() -> Dog {
return EvilDog()
}
}
當客戶端代碼根據工廠方法返回的實例的實際類型實現不同的行為時,您可能會遇到這種情況。 在那種情況下, AnimalFactory
應該實現用於提供將在客戶端代碼中使用的所有類型的實例的方法:
class AnimalFactory {
func getDog() -> Dog {
return EvilDog()
}
func getCat() -> Cat {
return Cat()
}
}
func trainAnimal(iLikeDogs: Bool, animalFactory: AnimalFactory) {
if iLikeDogs {
let dog = animalFactory.getDog()
dog.voice()
dog.sit() // only dog can sit
} else {
let cat = animalFactory.getCat()
cat.voice()
}
}
實際上,存在三種模式- 工廠 , 抽象工廠和工廠方法 。 您可以在此處了解差異。
協議可以由幾個實體符合 (在你的情況下,類SubClass
),但協議本身並不知道這所符合它的實體。 由於您的createFactory()
方法返回的是類型(協議)的IInterface
而不是類型的SubClass
,因此即使將SubClass
對象作為返回值發送,按原樣返回也不會知道特定於SubClass
成員。
let mgr = Factory.createFactory() /* Type: let mgr: IInterface */
當嘗試在實例mgr
上調用成員SubClassMethod
(或該SubClassMethod
任何未知成員,例如.foo
,也很明顯
錯誤:類型為“ IInterface”的值沒有成員“ SubClassMethod”
總結起來,符合協議的類型將可以訪問該協議中的所有藍圖方法和屬性,但是可以將協議的實例用作類型(如果您在內部沒有Self或任何關聯的類型,則可以接受您的協議)對碰巧符合該協議的其他類型的方法和屬性一無所知。
如下所述,如果您知道IInterface
類型的返回IInterface
是某種類型,則可以嘗試將類型轉換( as?
)轉換為該類型,例如... as? SubClass
... as? SubClass
。 請再次注意,協議IInterface
不知道符合該協議的類型,因此不能斷言這種類型轉換在編譯時是成功的。 嚴格來說,這是由您作為開發人員來控制的,如果您不小心,可能會導致運行時異常(例如,使用不安全的方法,如強制轉換as!
)。 現在,如果函數始終返回SubClass
類型,則最好將其簽名更改為
class func createFactory() -> SubClass {
保留IInterface
返回的可能用例是,如果createFactory()
實際上確實返回了均符合IInterface
協議的不同類型 。 在這種情況下,您可以安全地在createFactory()
返回值上使用switch
塊,以對符合IInterface
不同已知類型(開發人員已知 createFactory()
執行類型轉換,如下所示
protocol IInterface {
func InterfaceMethod() -> Void
}
public class SubClass: IInterface {
init() {}
func InterfaceMethod() { }
public func SubClassMethod() { }
}
public class AnotherClass: IInterface {
init() {}
func InterfaceMethod() { }
public func AnotherClassMethod() { }
}
public class Factory {
class func createFactory() -> IInterface {
if arc4random_uniform(5) > 2 {
return SubClass()
}
else {
return AnotherClass()
}
}
}
調用工廠方法時將塊switch
為返回:
switch(Factory.createFactory()) {
case let mgr as SubClass:
print("Subclass")
mgr.SubClassMethod()
case let mgr as AnotherClass:
print("AnotherClass")
mgr.AnotherClassMethod()
// default case
case let mgr as IInterface:
print("Unknown specific regarding return type")
}
最后,以下SO問題的答案可能對您有價值
您的let mgr
的類型為IInterface
,實際上沒有SubClassMethod
。
如果您知道Factory.createFactory()
返回SubClass
,則可以像這樣將其SubClass
為SubClass
:
let mgr = Factory.createFactory() as! SubClass
然后let mgr
成為SubClass
類型,您應該可以調用mgr.SubClassMethod
。
但是,即使您將類命名為Factory,您的示例也與工廠設計模式無關。 查看@mixel的答案以了解詳細信息。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.