Enums 与静态工厂相比,何时使用具有关联值的枚举?
在Swift中,您可以定义枚举并通过关联的值为其指定属性,例如:Enums 与静态工厂相比,何时使用具有关联值的枚举?,enums,swift,factory,Enums,Swift,Factory,在Swift中,您可以定义枚举并通过关联的值为其指定属性,例如: protocol SizeEnum { var length : Double? { get } // Length should be >= 0 - has to be an Optional for errors } enum SizesEnum : SizeEnum { case Short(length : Double) // 0 <= length <= maxShort c
protocol SizeEnum {
var length : Double? { get } // Length should be >= 0 - has to be an Optional for errors
}
enum SizesEnum : SizeEnum {
case Short(length : Double) // 0 <= length <= maxShort
case Long(length : Double) // length > maxShort
private static let maxShort = 1.0
var length : Double? {
get {
switch self {
case let .Short(length):
if length >= 0 && length <= SizesEnum.maxShort { // Need to error check every access
return length
}
case let .Long(length):
if length > SizesEnum.maxShort { // Need to error check every access
return length
}
}
return nil // There was an error
}
}
}
SizesEnum.Short(length: 0.5).length // [Some 0.5]
SizesEnum.Short(length: 2).length // nil
SizesEnum.Long(length: 2).length // [Some 2.0]
SizesEnum.Long(length: -1).length // nil
这可能是enum
的最佳示例,因为不需要进行错误检查,但即使如此,出厂版本仍具有竞争力。可选的
示例非常简单,您甚至不需要工厂,只需直接创建一些。注意None
如何不使用任何存储
条形码示例显示了工厂技术有多好;实际上,并非所有4个Int
s的集合都是有效的UPCA,也并非所有String
s都是有效的QR码,因此您需要进行错误检查,这对于enum
s来说是一件痛苦的事情。以下是出厂版本:
class Barcode { // Note seperate storage for each case
class UPCABarcode : Barcode {
let type : Int, l : Int, r : Int, check : Int
private init(type : Int, l : Int, r : Int, check : Int) {
(self.type, self.l, self.r, self.check) = (type, l, r, check)
}
}
class func UPCA(#type : Int, l : Int, r : Int, check : Int) -> UPCABarcode? {
if ok(type: type, l: l, r: r, check: check) {
return UPCABarcode(type: type, l: l, r: r, check: check)
}
return nil
}
class func QRCode(#s : String) -> Barcode? { // Have not expanded this case; use same pattern as UPCA
return Barcode()
}
private init() {} // Prevent any other types of Barcode
class func ok(#type : Int, l : Int, r : Int, check : Int) -> Bool {
return true // In practice has to check supported type, range of L and R, and if check digit is correct
}
}
Barcode.UPCA(type: 0, l: 1, r: 2, check: 3)
如果使用enum
版本的Barcode
,则每次使用Barcode
时都必须检查其有效性,因为无法阻止无效的条形码。而工厂版本在创建时进行检查。请注意,Barcode
没有存储,而UPCA
有自定义存储。我没有编写QRCode
,因为它使用了与UPCA
相同的设计模式
我的印象是,
enum
版本在教程中看起来很棒,但在实践中很快就会因为错误处理而变得痛苦。我相信最大的杀手级用例是可选的。它内置于语言中,但可选的是枚举:
enum Optional<T> {
case None
case Some(T)
}
对于结构,将有大量浪费的成员变量和一个混乱的接口来建模这类数据
我认为,如果对每种情况都使用相同的类型,那么对枚举使用关联值是没有意义的。在这种情况下,成员变量更干净。关联值的重点是更准确地建模某些类型的数据。最有用的情况是类型的不同实例可以有不同的关联数据。这可能是通过子类实现的,但是需要向下转换才能访问更多特定的变量,并且声明将更加详细。枚举是表示这类数据的简洁方法
另一个例子是web请求:
struct NetRequest {
enum Method {
case GET
case POST(String)
}
var URL: String
var method: Method
}
var getRequest = NetRequest(URL: "http://drewag.me", method: .GET)
var postRequest = NetRequest(URL: "http://drewag.me", method: .POST("{\"username\": \"drewag\"}"))
当我想到“enum”时,我一点也不想到“工厂”。通常,工厂用于更大更复杂的类结构。枚举应该是非常小的数据块,没有什么逻辑。谢谢你的评论,我编辑了原文以给出回应,因为我想展示我在评论中做不到的代码。@HowardLovatt,你实现可选的例子比枚举要复杂得多,我认为你太依赖Java模式了。为什么不在枚举上使用validate()->Bool
方法呢?我认为枚举对您来说似乎很痛苦,因为您希望使用现有的设计模式。老实说,从一眼就能理解工厂模式的角度来看,你给出的每一个工厂模式的例子对我来说都是难以置信的痛苦。为无效对象返回nil
不如使用validate
方法清晰。不过我相信这是个人的偏好
enum Optional<T> {
case None
case Some(T)
}
enum Barcode {
case UPCA(Int, Int, Int, Int)
case QRCode(String)
}
struct NetRequest {
enum Method {
case GET
case POST(String)
}
var URL: String
var method: Method
}
var getRequest = NetRequest(URL: "http://drewag.me", method: .GET)
var postRequest = NetRequest(URL: "http://drewag.me", method: .POST("{\"username\": \"drewag\"}"))