Swift:工厂模式,子类方法不可见

时间:2016-01-16 10:19:00

标签: ios swift factory factory-pattern

我是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,也会引发错误

  

IInterface类型的值没有成员SubClassMethod

我相信我只会通过协议方法公开,尽管通过工厂

返回了SubClass对象

我浏览过的所有示例都只显示了如何使用协议指定的方法,但我还没有看到一个示例,它显示了如何使用子类自己的方法而不是协议方法

3 个答案:

答案 0 :(得分:5)

你错过了工厂模式的观点。 Factory模式的思想是提供具有特定返回类型和返回实例的方法,这些实例具有此类型或从此类型继承(如果它是class类型)或符合此类型(如果它&# 39; s 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方法不应该推测其返回值并尝试将其强制转换为具体类。这完全破坏了使用工厂模式的重点。

正如您在上面的示例中看到的那样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()
    }
}

实际上有三种模式 - 工厂抽象工厂工厂方法。您可以阅读差异here

答案 1 :(得分:1)

协议可以符合多个实体(在您的情况下,类SubClass),但协议本身并不知道哪些实体符合。由于您的createFactory()方法会返回类型(协议)IInterface,而不是SubClass类型,因此返回原样将不知道特定于SubClass的成员,即使是SubClass 1}}对象作为返回发送。

let mgr = Factory.createFactory() /* Type: let mgr: IInterface */

当尝试在实例SubClassMethod

上调用成员.foo(或任何未知成员,例如mgr)时,这也很明显
  

错误:'IInterface'类型的值没有成员'SubClassMethod'

要包装它,符合协议的类型将可以访问该协议中的所有蓝图方法和属性,但是作为类型使用的协议实例(如果您没有Self或任何类型,则可以接受)协议中的相关类型)对于符合该协议的其他类型的方法和属性一无所知。

如下所述,如果知道IInterface类型的返回属于某种类型,那么您可以尝试对此类型进行类型转换(as?),例如... as? SubClass。但是请注意,协议IInterface不知道哪些类型符合它,这种类型转换不能在编译时声明为成功;这严格来说是您作为开发人员控制的事情,如果您不小心(例如使用强制转换as!等非安全方法),可能会导致运行时异常。现在,如果函数始终返回SubClass类型,您也可以将其签名更改为

class func createFactory() -> SubClass {

尽可能保持IInterface返回的用例是createFactory()实际上返回不同类型,它们都符合IInterface协议。在这种情况下,您可以安全地使用switch块来createFactory()返回,以便对您符合{{1如下

IInterface
在调用工厂方法时

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

最后,对以下SO问题的回答可能对您有价值

答案 2 :(得分:0)

let mgr类型IInterface确实没有SubClassMethod

如果您知道Factory.createFactory()返回SubClass,则可以将其转换为SubClass

let mgr = Factory.createFactory() as! SubClass

然后let mgr类型为SubClass,您应该可以致电mgr.SubClassMethod

尽管如此,即使您将类命名为Factory,您的示例也与工厂设计模式无关。有关详细信息,请查看@ mixel的答案。