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

decorator_design_patterns_proSwift_ru2

 

В этой статье мы разберем шаблон программирования Декоратор (Decorator) на языке программирования Swift в среде разработки Xcode.

Decorator

Класный пример декоратора – различные чехлы для новых телефонов.  Для начала у нас есть телефон. Но так как телефон дорогой, мы будем очень счастливы если он не разобьется при любом падении – потому мы покупаем чехол для него. То есть, к уже существующему предмету мы добавили функционал защиты от падения. Ну еще мы взяли стильный чехол – теперь наш телефон еще и выглядит отлично. А потом мы докупили съемный объектив, с помощью которого можно делать фотографии с эффектом “рыбьего глаза”. Декорировали наш телефон дополнительным функционалом:)

Вот, приблизительно так выглядит реально описание паттерна декоратор. Теперь описание GoF:
Декоратор добавляет некий функционал уже существующему объекту.

Когда использовать этот паттерн:

1. Вы хотите добавить определенному объекту дополнительные возможности, при этом не задевая и не меняя других объектов

2. Дополнительные возможности класса – опциональны

Радость Swift в данном случае – это использование расширений extension. Я не буду детально описывать расширения в этой статье, но в двух словах все же расскажу: Расширения – это возможность расширить любой объект дополнительным функционалом без использования механизма наследования. Давайте возьмем супер простой пример – декорирование Cocoa классов. К примеру добавим новый метод для объекта NSDate:

//
// proSwift.ru
//

extension NSDate {
    func convertDateToString() -> String  {
        let formatter = NSDateFormatter()
        formatter.dateFormat = "dd-0M-yyyy"
        return formatter.stringFromDate(self)
    }
}

Как видим наше расширение определяет только один метод “convertDateToString”, который дату форматирует в текстовый формат

Собственно, это все.

//
// proSwift.ru
//

let dateNow = NSDate()
print("Сейчас: \(dateNow.convertDateToString())")

Лог выглядит ожидаемо:

Сейчас: 25-07-2016

Пример с GitHub

decorator_design_patterns_proSwift_ru

Шаблон декоратор используется для расширения или изменения функциональности объектов во время выполнения программы, обернув их в объект класса декоратора. Это обеспечивает гибкую альтернативу наследованию для изменения поведения.

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

protocol Coffee {
    func getCost() -> Int
    func getIngredients() -> String
}

class SimpleCoffee: Coffee {
    func getCost() -> Int {
        return 60
    }
    
    func getIngredients() -> String {
        return "Coffee"
    }
}

class CoffeeDecorator: Coffee {
    private let decoratedCoffee: Coffee
    private let ingerientSeparator: String = ", "
    
    required init(decoratedCoffee: Coffee) {
        self.decoratedCoffee = decoratedCoffee
    }
    
    func getCost() -> Int {
        return decoratedCoffee.getCost()
    }
    
    func getIngredients() -> String {
        return decoratedCoffee.getIngredients()
    }
}


class Milk:CoffeeDecorator {
    
    required init(decoratedCoffee: Coffee) {
        super.init(decoratedCoffee: decoratedCoffee)
    }
    
    override func getCost() -> Int {
        return decoratedCoffee.getCost() + 20
    }
    
    override func getIngredients() -> String {
        return decoratedCoffee.getIngredients() + ingerientSeparator + "Milk"
    }
}

class WhipCoffee: CoffeeDecorator {
    required init(decoratedCoffee: Coffee) {
        super.init(decoratedCoffee: decoratedCoffee)
    }
    
    override func getCost() -> Int {
        return decoratedCoffee.getCost() + 25
    }
    
    override func getIngredients() -> String {
        return decoratedCoffee.getIngredients() + ingerientSeparator + "Whip"
    }
}


var someCoffee = SimpleCoffee()
print("Стоимость напитка: \(someCoffee.getCost()), а ингредиенты: \(someCoffee.getIngredients())")
let milkCoffee = Milk(decoratedCoffee: someCoffee)
print("Стоимость напитка: \(milkCoffee.getCost()), а ингредиенты: \(milkCoffee.getIngredients())")
let premiumCoffee = WhipCoffee(decoratedCoffee: milkCoffee)
print("Стоимость напитка: \(premiumCoffee.getCost()), а ингредиенты: \(premiumCoffee.getIngredients())")

Напитки, которые унаследованы от кофейного декоратора имеют свои стоимость и ингредиенты.

1 Comment on “Шаблоны программирования на Swift: Decorator

  1. У класса CoffeeDecorator переменные decoratedCoffee: Coffee и ingerientSeparator: String = «, » должны быть public, иначе не взлетит

Добавить комментарий для Евгений Отменить ответ

Ваш адрес email не будет опубликован.

*

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