Фабричный шаблон
Часть раздела Объектно-ориентированное программирование путешествия по Swift на Coddy. Урок 43 из 57.
Паттерн фабрика помещает создание объектов в одно место. Вызывающий код запрашивает то, что ему нужно, часто по имени или типу, и получает готовый объект, не зная, какой конкретный тип был создан:
protocol Shape { func area() -> Double }
struct Square: Shape { let side: Double; func area() -> Double { side * side } }
struct Circle: Shape { let r: Double; func area() -> Double { 3 * r * r } }
enum ShapeFactory {
static func make(_ kind: String, size: Double) -> (any Shape)? {
switch kind {
case "square": return Square(side: size)
case "circle": return Circle(r: size)
default: return nil
}
}
}
print(ShapeFactory.make("square", size: 3)!.area())
print(ShapeFactory.make("hexagon", size: 3) == nil)Вывод:
9.0
trueВызывающая сторона зависит только от протокола. Добавление новой формы означает изменение фабрики, а не каждого места, где создаются формы:
protocol Notifier { func send(_ m: String) -> String }
struct Email: Notifier { func send(_ m: String) -> String { "email: \(m)" } }
struct SMS: Notifier { func send(_ m: String) -> String { "sms: \(m)" } }
func makeNotifier(for user: String) -> any Notifier {
user.hasSuffix("@mail.com") ? Email() : SMS()
}
print(makeNotifier(for: "ada@mail.com").send("hi"))
print(makeNotifier(for: "555-0100").send("hi"))Вывод:
email: hi
sms: hiСтатические фабричные методы в самом типе — это более лёгкая форма паттерна. Они дают имена распространённым способам создания значения:
struct Color {
let r: Int, g: Int, b: Int
static func gray(_ v: Int) -> Color { Color(r: v, g: v, b: v) }
static let white = Color(r: 255, g: 255, b: 255)
}
print(Color.gray(100).g)
print(Color.white.b)Вывод:
100
255Перечисление без вариантов, такое как ShapeFactory, — распространённый способ сгруппировать фабричные функции: его нельзя создать, поэтому оно используется исключительно как пространство имён.
enum ShapeFactory { // нет cases: нельзя создать
static func make(_ kind: String, size: Double) -> (any Shape)? { ... }
}Задание
ЛегкоНапишите фабрику для тарифных планов. Протокол Plan содержит name и price(forUsers:) -> Int. Реализуйте Free (0 и только для 3 пользователей включительно: при большем количестве цена равна -1, что означает недопустимое количество пользователей), Team (10 за пользователя) и Enterprise (фиксированные 500 плюс 5 за каждого пользователя свыше 100). Завершите реализацию PlanFactory.make(_:), которая возвращает план для free, team или enterprise, а в остальных случаях — nil.
Предоставленный код считывает строки в формате plan,users и выводит team for 12 users: 120, free does not allow 5 users или unknown plan: gold.
Ваш код должен находиться в файлах Plan.swift, Free.swift, Team.swift, Enterprise.swift и PlanFactory.swift. В main.swift содержится предоставленный код ввода-вывода, и его нельзя редактировать.
Попробуйте сами
// Предоставленный код ввода/вывода: оставьте его как есть
var input: [String] = []
while let line = readLine() { input.append(line) }
for line in input {
let p = line.split(separator: ",").map(String.init)
let users = Int(p[1])!
guard let plan = PlanFactory.make(p[0]) else {
print("unknown plan: \(p[0])")
continue
}
let price = plan.price(forUsers: users)
print(price < 0 ? "\(plan.name) does not allow \(users) users" : "\(plan.name) for \(users) users: \(price)")
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Классы и объекты
Работа с файламиОпределение классовМетоды и selfИнициализаторыКлассы — это ссылкиПовторение — читательский билет4Инкапсуляция
Контроль доступаТолько чтение извнеЗащита состоянияИнициализаторы с возможностью сбояПовторение — банковский счёт7Полиморфизм и обобщения
ПолиморфизмПриведение типовОбобщённые функцииОбобщённые типыПовторение — калькулятор фигур10Паттерны проектирования. Часть 2
Паттерн делегированияПаттерн декораторПаттерн строительПаттерн состояния2Структуры и типы-значения
СтруктурыСемантика значенийИзменяющие методыСтруктура или классПовторение — элемент инвентаря5Наследование
ПодклассыПереопределение методовИнициализаторы и superfinal и иерархииПовторение — иерархия сотрудников8Стандартные протоколы
CustomStringConvertibleEquatableComparableHashableПовторение — пользовательская сортировка11Проект: Управление библиотекой
Книги и читателиВыдача книгПотренируйтесь самостоятельно: Песочница Swift