我是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对象我浏览过的所有示例都只显示了如何使用协议指定的方法,但我还没有看到一个示例,它显示了如何使用子类自己的方法而不是协议方法
答案 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的答案。