2016-05-31 41 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