Подтвердить что ты не робот

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(), где параметры являются необязательными? Если бы вы могли указать мне в сторону терминов или концепций для поиска, это было бы здорово.

4b9b3361

Ответ 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(), когда у вас нет других атрибутов для установки.