Swift Initialize Struct с дополнительными хранимыми свойствами
Я новичок в Swift, и я пытаюсь использовать его, используя Structs с дополнительными свойствами. Я сделал довольно много поиска и получил что-то, что работает, но он чувствует себя невероятно неэффективным, поэтому задавался вопросом, есть ли лучший/более управляемый способ достижения моей цели.
Я хотел бы использовать 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 Cafe", website: "http://www.davescafe.com")
Business(busName: "Sarah Brewhouse", address: "41 Acacia Ave, Smalltown")
Нет ли способа создать какой-либо init(), где параметры являются необязательными? Если бы вы могли указать мне в сторону терминов или концепций для поиска, это было бы здорово.
Ответы
Ответ 1
Использовать значения по умолчанию:
init(busName: String, website: String? = nil, address: String? = nil) {
self.name = busName
self.web = website
self.address = address
}
Затем вы можете вызвать init следующим образом:
_ = Business(busName: "Foo")
_ = Business(busName: "Foo", website: "www.foo.bar")
_ = Business(busName: "Foo", address: "bar")
_ = Business(busName: "Foo", website: "www.foo.bar", address: "bar")
Ответ 2
Одним из подходов, который вы можете брать с других языков ООП, является шаблон построителя параметров. Начните с статического метода, который возвращает построитель, затем добавьте методы для отдельных параметров и, наконец, вызовите 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 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()
, когда у вас нет других атрибутов для установки.