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's Cafe", website: "http://www.davescafe.com")

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

Нет ли способа создать какую-то функцию init (), где параметры являются необязательными? Если бы вы могли указать мне в направлении терминов или понятий для поиска, было бы здорово.

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

 dasblinkenlight31 мая 2016 г., 21:46
@ AMomchilov Шутка, что шаблоны проектирования - это обходные пути для функций, отсутствующих в языке программирования. Шаблон Builder был введен в Java в первую очередь для компенсации отсутствующей в языке функции именованных параметров. Swift, с другой стороны, изначально решает эту проблему, поэтому главная причина использования компоновщика в Swift - возможность передавать параметры инициализатора по одному за раз.
 Alexander31 мая 2016 г., 22:12
В Java также не было параметров по умолчанию, поэтому вы можете вынуждать вас разбивать шаблон компоновщика для класса только с несколькими параметрами.
 Alexander31 мая 2016 г., 21:35
Построитель кажется ненужным для простого примера OP, но он может быть полезен, если OP намеревается масштабировать до большего количества полей.
Решение Вопроса

Используйте значения по умолчанию:

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")
 jtbandes31 мая 2016 г., 21:17
@ Джеймс лучший совет, который я могу предложить, ... попробуй! Что делать, если вы пишетеvar web: String - это работает? Если нет, какое сообщение об ошибке вы получаете?
 James01 июн. 2016 г., 00:54
Спасибо за разъяснение этого @NobodyNada - я был уверен, что прочитал что-нибудь о том, что nil автоматически устанавливается для опций ... Я не знал об особенностях (все еще разбираюсь в терминологии Swift и т. Д.)
 jtbandes31 мая 2016 г., 21:10
Да,String или жеString? это просто тип; это не имеет ничего общего со значением по умолчанию (если мы говорим о параметрах функции). Вы могли бы также иметь значение по умолчанию для параметра String, напримерinit(busName: String = "") хотя я думаю, что дополнительные опции - правильный путь для этого.
 James31 мая 2016 г., 21:16
@dasdom @jtbandes - большое спасибо вам обоим. Оно работает! Продолжение В: Где я инициализировал переменные в верхней части моего примера кода, я использовалvar web : String? это бессмысленно / неправильно? Я думал, что мне нужно использовать? потому что эти переменные являются «необязательными».
 jtbandes31 мая 2016 г., 21:08
Это должно бытьString? и неString.
 NobodyNada01 июн. 2016 г., 00:28
@James Значение автоматически устанавливается наnil если он является необязательным, и ему не было явно назначено значение, но только для переменных экземпляра, а не параметров метода.
 James31 мая 2016 г., 21:08
Спасибо @dasdom, я попытался с помощью? после типа (например,... website: String? ... как я думал, что с помощью этого синтаксиса автоматически установить значение на ноль. Это не сработало, поэтому я не пытался явно установить значение на ноль. Я попробую это сейчас.

Ваш ответ на вопрос