2016-05-31 33 views
25

我是一个Swift新手,我试图让我的头部使用具有可选属性的Structs。我做了很多搜索,并找到了一些可行的方法,但它感觉非常低效,所以想知道是否有更好/更易于管理的方式来实现我的目标。Swift使用可选的存储属性初始化Struct

我想用Structs来代表一个企业,但我并不知道哪些特定业务组合可能具有哪些特性组合。这似乎意味着我必须为每个可能的参数组合创建一个init()。

下面是一个简单的例子(我有很多属性):

import Foundation 

struct Business { 
    let name : String 
    var web : String? 
    var address: String? 

    // just the business name 
    init(busName: String) { 
     self.name = busName 
    } 

    // business name + website 
    init(busName: String, website: String) { 
     self.name = busName 
     self.web = website 
    } 

    // business name + address 
    init(busName: String, address: String) { 
     self.name = busName 
     self.address = address 
    } 

    // business name + website + address 
    init(busName: String, website: String, address: String) { 
     self.name = busName 
     self.web = website 
     self.address = address 
    } 
} 

然后我就可以初始化类是这样的:

Business(busName: "Dave's Cafe", website: "http://www.davescafe.com") 

Business(busName: "Sarah's Brewhouse", address: "41 Acacia Ave, Smalltown") 

有没有办法创造某种的init( )参数是可选的?如果你能指出我的方向或概念来寻找那将是很棒的。

回答

36

使用默认值:

init(busName: String, website: String? = nil, address: String? = nil) { 
    self.name = busName 
    self.web = website 
    self.address = address 
} 

然后,你可以调用init这样的:

,你可以从其他OOP语言借用
_ = Business(busName: "Foo") 
_ = Business(busName: "Foo", website: "www.foo.bar") 
_ = Business(busName: "Foo", address: "bar") 
_ = Business(busName: "Foo", website: "www.foo.bar", address: "bar") 
+1

那些应该是'String?'而不是'String'。 – jtbandes

+0

Thanks @dasdom我在类型之后尝试使用'?'(例如'... website:String?...',因为我认为使用该语法会自动将该值设置为零。不要试着明确地将值设置为零,我现在就试试吧 – James

+0

是的,'String'或'String?'只是一个类型;它与默认值没有多大关系(只要我们'你可能已经有了一个String参数的默认值,比如'init(busName:String =“”)'虽然我认为option是正确的选择 – jtbandes

9

一种方法是参数生成器模式。与返回建设者静态方法开始,再加入各个参数的方法,最后调用build()

let bakery = Business 
    .withName("Black Forest") 
    .andWebSite("www.blackforest.com") 
    .andAddress("1 Main St, Springfield, IA 98765") 
    .build() 

这里是一个框架实现,使这种API的:

class Business { 
    // Users never call this init, it's for the builder to use 
    init(name: String, webSite: String?, address: String?) { 
     ... 
    } 
    // Here is the method the users call: 
    static func withName(name: String) { 
     return BusinessBuilder(name) 
    } 
    // This class collects parameters before calling init 
    class BusinessBuilder { 
     var name : String 
     var webSite : String? 
     var address: String? 
     func andAddress(address: String) -> BusinessBuilder { 
      self.address = address 
      return self 
     } 
     func andWebSite(webSite: String) -> BusinessBuilder { 
      self.webSite = webSite 
      return self 
     } 
     func build() -> Business { 
      return Business(name, webSite, address) 
     } 
     init(name: String) { 
      self.name = name 
     } 
    } 
} 

这可以让您按照您认为合适的方式传递尽可能少的或尽可能多的初始化参数,并且可以在给定的情况下以任何顺序发现。

此方法的主要用途是当您不知道要获取哪些参数时,例如,它们来自XML或数据库时。您可以在循环中调用andXyz方法,然后在没有其他属性设置时调用build()

+0

Builder似乎不需要OP的简单例子,但如果OP打算扩展到更多领域,它可能会很有用。 – Alexander

+5

@AMomchilov有一个笑话,设计模式是编程语言中缺少的功能的变通方法。 Java中引入了构建器模式,主要是为了补偿语言中缺少的命名参数功能。另一方面,Swift原生地解决了这个问题,所以在Swift中使用构建器的主要原因是能够一次传递一个初始化参数。 – dasblinkenlight

+0

Java也没有默认的参数,这样可能迫使你不得不为仅有几个参数的类创建构建器模式。 – Alexander