好的,我有一个名为Environment
protocol Environment {
var rootURL: String {get}
}
然后是两个结构:
struct Production: Environment {
var rootURL = "www.api.mybackend.com/v1"
}
struct Development: Environment {
var rootURL = "www.api.mydevelopmentbackend.com/v1"
}
具有检索环境的函数的设置对象:
class Settings {
func getEnvironment<T>() -> T where T: Environment {
let environmentRaw = self.retreiveEnvironmentFromLocalStore()
switch environmentRaw {
case 0:
return Development() as! T
case 1:
return Production() as! T
default:
return Development() as! T
}
}
func retreiveEnvironmentFromLocalStore() -> Int {
//Realm, SQLLite, Core Date, I don't really care for this example.
//Let's just say it defaults to returning 1
}
}
我真的想继续向Protocol Oriented Programming方向移动,但现在当我在一个设置对象上调用此函数并尝试使用rootURL
属性时,编译器会抱怨它无法弄清楚类型。所以,为了更好地理解并找到解决方案:
1)如果我访问一个协议定义的属性,它至少知道返回类型是否符合?为什么它关心类型?
2)结构不具有遗传。我应该定义基类并忘记泛型吗?
3)我可以让我的getEnvironment
功能更好吗?我不喜欢强制施法,这似乎是一种代码味道。
4)我甚至在这里正确使用泛型吗?
编辑1:
要清楚,我想要一个函数返回一个我知道将具有此属性的结构。
答案 0 :(得分:3)
我是否在这里正确使用泛型?
不,我不这么认为。您说getEnvironment
将返回T
,它可以是客户端代码指定的任何类型,只要它实现Environment
即可。但是,该方法的实现不会这样做。它只返回两种Environment
,它返回的类型不是由客户端代码决定的。返回的类型取决于retreiveEnvironmentFromLocalStore
返回的内容。因此,在这种情况下,泛型不适合。
由于它返回的环境类型是由方法的实现决定的,而不是客户端代码,你应该在这里使用多态 - 让它返回Environment
代替:
func getEnvironment() -> Environment {
let environmentRaw = self.retreiveEnvironmentFromLocalStore()
switch environmentRaw {
case 0:
return Development()
case 1:
return Production()
default:
return Development()
}
}
答案 1 :(得分:1)
我真的想继续推进面向协议的编程方向
我建议您尝试以明确,可理解的代码方向移动,无论时尚方向如何。
这是你的功能声明:
func getEnvironment() - &gt; T其中T:环境
这表示getEnvironment()
将返回某种类型T
的对象,其中T
在编译时推断 ,基于调用{{}的代码1}}。
getEnvironment()
可以使用哪些类型?它可以是T
或Production
。例如,您可以写:
Development
这使得编译器可以推断let e: Production = Settings().getEnvironment()
在此调用站点返回getEnvironment()
(Production
}。
但是有一个问题:Environment
可能会尝试根据getEnvironment()
内的随机数生成器返回Development
。如果无法将retreiveEnvironmentFromLocalStore
投射到Development
,您将在运行时发生 。
为什么你认为Production
需要是通用的?根据您问题中的代码,它不应该是。
getEnvironment()
样式说明:Swift API Design Guidelines建议我们
根据副作用命名功能和方法
- 没有副作用的人应该读作名词短语,例如:
import Foundation protocol Environment { var rootURL: String {get} } struct Production: Environment { var rootURL = "www.api.mybackend.com/v1" } struct Development: Environment { var rootURL = "www.api.mydevelopmentbackend.com/v1" } class Settings { func getEnvironment() -> Environment { let environmentRaw = self.retreiveEnvironmentFromLocalStore() switch environmentRaw { case 1: return Production() default: return Development() } } func retreiveEnvironmentFromLocalStore() -> Int { return Int(arc4random()) } } let settings = Settings() let e = settings.getEnvironment()
。
除非x.distance(to: y), i.successor()
中的方法有重要的副作用,否则更好的名称将是Settings
和environment()
。