В этот раз я бы хотел немного поговорить о еще одном порождающем шаблоне проектирования из арсенала «Банды четырех» – «Строителе» («Builder»). Так вышло, что в ходе получения своего (пусть и не слишком обширного) опыта, я довольно часто видел, чтобы паттерн использовался в «Java»-коде вообще и в «Android»-приложениях в частности. В «iOS» же проектах, будь они написаны на «Swift» или «Objective-C», шаблон встречался мне довольно редко. Тем не менее, при всей своей простоте, в подходящих случаях он может оказаться довольно удобным и, как модно говорить, мощным.  Шаблон используется для замены сложного процесса инициализации конструированием нужного объекта шаг за шагом, с вызовом финализирующего метода в конце. Шаги при этом могут быть опциональными и не должны иметь строгой последовательности вызова.  В случаях, когда нужный «URL» не зафиксирован, а конструируется из составляющих (например, адреса хоста и относительного пути до ресурса), вы наверняка пользовались удобным механизмом URLComponents из библиотеки «Foundation». URLComponents – это, по большей части, просто класс, объединяющий множество переменных, которые хранят значения тех или иных компонентов «URL», а также свойство url, которое возвращает соответствующий текущему набору компонентов «URL». Например: По сути, приведенный выше пример использования – это реализация паттерна «Строитель». URLComponents в этом случае выступает в роли собственно строителя, присвоение различным его свойствам (scheme, host и пр.) значений – это инициализация будущего объекта по шагам, а вызов свойства url – это подобие финализируещего метода. В комментариях развернулись жаркие баталии о «RFC»-документах, описывающих «URL» и «URI», поэтому, чтобы быть более точным, предлагаю для примера считать, что мы говорим только об «URL» удаленных ресурсов, и не принимаем во внимание такие «URL»-схемы, как, скажем, «file». Вроде бы все хорошо, если пользоваться таким кодом нечасто и знать все его тонкости. Но что, если что-нибудь забыть? Например, что-нибудь важное, как адрес хоста? Как вы думаете, что будет результатом выполнения следующего кода? Мы работаем со свойствами, а не методами, и никаких ошибок «выброшено» точно не будет. «Финализирующее» свойство url возвращает опциональное значение, так может быть, мы получим nil? Нет, мы получим вполне полноценный объект типа URL с бессмысленным значением – «https:/some/path». Поэтому мне пришло в голову поупражняться написанием собственного «строителя» на основе описанного выше «API». Не смотря на сказанное выше, я считаю URLComponents хорошим и удобным «API» для сборки «URL» из составных частей и, наоборот, «парсинга» составных элементов известного «URL». Поэтому на его основе мы сейчас и напишем собственный тип, собирающий «URL» из частей и обладающий (предположим) нужным нам в данный момент «API». Во-первых, хочется избавиться от разрозненной инициализации путем присваивания новых значений всем нужным свойствам. Вместо этого реализуем возможность создания экземпляра строителя и присвоение значений всем свойствам с помощью методов, вызываемых по цепочке. Цепочка заканчивается финализирующим методом, результатом вызова которого и будет соответствующий экземпляр URL. Возможно, вы встречали на своем жизненном пути что-нибудь вроде StringBuilder у «Java» – примерно к такому «API» мы сейчас и будем стремиться. Чтобы иметь возможность вызывать методы-шаги по цепочке, каждый из них должен возвращать экземпляр текущего строителя, внутри которого будет храниться соответствующее изменение. По этой причине, а также чтобы избавиться от множественного копирования объектов и от пляски вокруг mutating-методов, особенно не задумываясь, объявим наш строитель классом: Объявим методы, задающие параметры будущего «URL», с учетом перечисленных выше требований: Заданные параметры мы сохраняем в частных свойствах класса для дальнейшего использования финализируюим методом. Еще одна дань «API», на котором мы основываем наш класс – это свойство path, которое, в отличие от всех соседних свойств, не является опциональным, а в случае отсутствия относительного пути хранит в качестве своего значения пустую строку. Чтобы написать этот, собственно, финализирующий метод необходимо подумать еще о нескольких вещах. Во-первых, «URL» обладает некоторыми частями, без которых он, как было обозначено в начале, перестает иметь смысл – это scheme и host. Первого мы «наградили» значением по умолчанию, поэтому забыв о нем, мы все равно получим, скорее всего, ожидаемый результат. Со вторым дела обстоят чуть сложнее: ему нельзя присвоить какое-то значение по умолчанию. В таком случае у нас есть два пути: в случае отсутствия значения у этого свойства либо вернуть nil, либо выбросить ошибку и предоставить клиентскому коду самому решать, что с ней делать. Второй вариант сложнее, но зато позволит недвусмысленно указать на конкретную ошибку программиста. Пожалуй, для примера, по этому пути мы и пойдем. Еще один интересный момент связан со свойствами user и password: они имеют смысл только в том случае, если используются одновременно. Но что, если программист забудет присвоить одно из этих двух значений? И, наверное, последнее, что необходимо учесть – это то, что результатом финализирующего метода мы хотим иметь значение свойства url URLComponents, а оно, в данном случае, не очень кстати является опциональным. Хотя при любом сочетании заданных значений свойств nil мы не получим. (Значение будет отсутствовать только у пустого, только что созданного, экземпляра URLComponents.) Чтобы преодолеть это обстоятельство, можно использовать ! – оператор «forced unwrapping». Но вообще-то не хотелось бы поощрять его использование, поэтому в нашем примере мы немного абстрагируемся от знаний тонкостей «Foundation» и будем считать обсуждаемую ситуацию системной ошибкой, возникновение которой не зависит от нашего кода. Итак: Вот, пожалуй, и все! Теперь покомпонентное создание «URL» из примера в начале может выглядеть так: Разумеется, использование try вне блока do-catch или без оператора ? при возникновении ошибки заставит программу завершиться аварийно. Но мы предоставили «клиенту» возможность обрабатывать ошибки так, как он сочтет необходимым. Да, и еще одна полезная особенность пошагового конструирования с помощью этого шаблона – возможность помещать шаги в разных частях кода. Не самый частый «кейс», но тем не менее. Спасибо akryukov за напоминание! Шаблон экстремально прост для понимания, а все простое – как известно, гениально. Или наоборот? Ну, неважно. Главное, что я, не покривив душой могу сказать, что он (шаблон), уже случалось, выручал меня в решении задач по созданию больших и сложных процессов инициализации. Например, процесс подготовки сессии связи с сервером в библиотеке, которую я писал для одного сервиса почти два года назад. Кстати, код – «open source» и, при желании, с ним вполне можно ознакомиться. (Хотя, конечно, с тех пор много воды утекло, и к этому коду прикладывались и другие программисты.) Другие мои посты о шаблонах проектирования: А это мой «Twitter», чтобы удовлетворить гипотетический интерес к моей публично-профессиональной активности. (iOS) Software Development Engineer