Шаблоны программирования на Swift: Factory

Продолжаем изучать шаблоны программирования или шаблоны проектирования на языке Swift на реальных примерах. В предыдущей статье Шаблоны программирования на Swift: Prototype мы рассмотрели шаблон Prototype, а в данной статье мы будем разбираться с шаблоном Фабрика — Factory

Factory Method.

Еще один порождающий паттерн, довольно прост и популярен.Паттерн позволяет переложить создание специфических объектов, на наследников родительского класса, потому можно манипулировать объектами на более высоком уровне, не заморачиваясь объект какого класса будет создан. Частенько этот паттерн называют виртуальный конструктор, что по моему мнению более выражает его предназначение.

Когда использовать:

1. Мы не до конца уверены объект какого типа нам необходим.
2. Мы хотим чтобы не родительский объект решал какой тип создавать, а его наследники.

Почему хорошо использовать:

Объекты созданные фабричным методом – схожи, потому как у них один и тот же родительский объект. Потому, если локализировать создание таких объектов, то можно добавлять новые типы, не меняя при это код который использует фабричный метод.

Пример:

Давайте представим, что мы такой неправильный магазин в котором тип товара оценивается по цене:) На данный момент товар есть 2х типов – Игрушки и Машины.

В чеке мы получаем только цены, и нам надо сохранить объекты которые куплены.

Для начала создадим клас Product. Его реализация нас особо не интересует, хотя он может содержать в себе общие для разных типов товаров методы (сделано для примера, мы их особо не используем):

//
// proSwift.ru
//

class Product {
    let price: Int
    let name: String
    
    init(price: Int, name: String) {
        self.price = price
        self.name = name
    }
    
    func getTotalPrice(sum: Int) -> Int {
        return self.price + sum
    }
    
    func saveObject() {
        print(" Saving product \(self.name) to database")
    }
}

Создадим два наследника

//
// proSwift.ru
//


class Toy: Product {
    override func saveObject() {
        print(" Saving product \(self.name) into TOYS database")
    }
}

class Car: Product {
    override func saveObject() {
        print(" Saving product \(self.name) into CARS database")
    }
}

Ну теперь мы практически в плотную подошли к нашему паттерну Factory. Собственно, теперь надо создать метод, который будет по цене определять что же за продукт у нас в чеке, и создавать объект необходимого типа.

//
// proSwift.ru
//

class ProductGenerator {
    
    func getProduct(price: Int) -> Product? {
        if price > 0 && price < 100 {
            let product = Toy(price: price, name: "Transformer")
            return product
        }
        if price > 100 {
            let product = Car(price: price, name: "Audi")
            return product
        }
        return nil
    }
}

Для проверки работы будем использовать метод, который использует ProductGenerator и выведем в лог продукты, которые создала наша фабрика:

//
// proSwift.ru
//

func saveExpenses(aPrice: Int) {
    let pg = ProductGenerator()
    let expense = pg.getProduct(aPrice)
    
    expense?.saveObject()
}


saveExpenses(50)
saveExpenses(80)
saveExpenses(90)
saveExpenses(150)
saveExpenses(560)
saveExpenses(5)
saveExpenses(105)

Лог в консоле:

 Saving product Transformer into TOYS database
 Saving product Transformer into TOYS database
 Saving product Transformer into TOYS database
 Saving product Audi into CARS database
 Saving product Audi into CARS database
 Saving product Transformer into TOYS database
 Saving product Audi into CARS database

Итак, шаблон проектирования Фабрика,  или Factory используется для замены конструктора класса, абстрагируя процесс генерации объекта так, чтобы тип экземпляра мог быть определен во время выполнения программы.

И реальный пример использования шаблона проектирования Factory

// 
// proSwift.ru
//
//https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/source/creational/factory.swift



protocol Currency {
    func symbol() -> String
    func code() -> String
}

class Euro : Currency {
    func symbol() -> String {
        return "€"
    }
    
    func code() -> String {
        return "EUR"
    }
}

class UnitedStatesDolar : Currency {
    func symbol() -> String {
        return "$"
    }
    
    func code() -> String {
        return "USD"
    }
}

enum Country {
    case UnitedStates, Spain, UK, Greece
}

enum CurrencyFactory {
    static func currencyForCountry(country:Country) -> Currency? {

        switch country {
            case .Spain, .Greece :
                return Euro()
            case .UnitedStates :
                return UnitedStatesDolar()
            default:
                return nil
        }
        
    }
}

let noCurrencyCode = "No Currency Code Available"

print(CurrencyFactory.currencyForCountry(.Greece)?.code() ?? noCurrencyCode)
print(CurrencyFactory.currencyForCountry(.Spain)?.code() ?? noCurrencyCode)
print(CurrencyFactory.currencyForCountry(.UnitedStates)?.code() ?? noCurrencyCode)
print(CurrencyFactory.currencyForCountry(.UK)?.code() ?? noCurrencyCode)

Т.к. в фабрике мы не обрабатывали страну UK фабрика не вернет валюту для этой страны. Соответсвенно лог будет выглядеть так:

EUR
EUR
USD
No Currency Code Available

Метки:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*

Этот сайт использует Akismet для борьбы со спамом. Узнайте как обрабатываются ваши данные комментариев.