簡體   English   中英

迅捷:工廠模式,子類方法不可見

[英]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 ,則可以像這樣將其SubClassSubClass

let mgr = Factory.createFactory() as! SubClass

然后let mgr成為SubClass類型,您應該可以調用mgr.SubClassMethod

但是,即使您將類命名為Factory,您的示例也與工廠設計模式無關。 查看@mixel的答案以了解詳細信息。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM