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

 

strategy-design-temlate_proSwift_ru

В этой статье мы рассмотрим шаблон программирования Стратегия (Strategy) на Swift в среде разработки XCode

Strategy

Если Ваша девушка злая, вы скорее всего будете общаться с ней осторожно. Если на вашем проетке завал, то вероятнее всего вы не будете предлагать в команде вечерком дернуть пива или поиграть в компьютерные игры. В различных ситуациях, у нас могут быть очень разные стратегии поведения. К примеру, в приложении вы можете использовать различные алгоритмы сжатия, в зависимости от того с каким форматом картинки вы работаете, или же куда вы хотите после этого картинку деть. Вот мы и добрались до паттерна Стратегия.
Также отличным примером может быть MVC паттерн – в разных случаях мы можем использовать разные контроллеры для одного и того же View (к примеру авторизированный и не авторизированный пользователь).
Паттерн Стратегия определяет семейство алгоритмов, которые могут взаимозаменяться.
Когда использовать паттерн:

  1. Вам необходимы различные алгоритмы
  2. Вы очень не хотите использовать кучу вложенных If-ов
  3. В различных случаях ваш класс работает по разному

Давайте напишем пример – RPG игра, в которой у вас есть различные стратегии нападения Вашими персонажами:) Каждый раз когда вы делаете ход, ваши персонажи делают определенное действие. Итак, для начала управление персонажами!
Создадим базовую стратегию:

//
// proSwift.ru
//

protocol BasicStrategy {
    func actionPerson1()
    func actionPerson2()
    func actionPerson3()
}

Как видно из кода стратегии – у нас есть 3 персонажа, каждый из которых может совершать одно действие! Давайте научим персонажей нападать!

//
// proSwift.ru
//

class AttackStrategy: BasicStrategy {

    func actionPerson1() {
        print("Герой 1 - атакуй всех врагов")
    }
    
    func actionPerson2() {
        print("Герой 2 - атакуй всех врагов")
    }

    func actionPerson3() {
        print("Герой 3 - атакуй всех врагов")
    }
}

При использовании такой стратегии наши персонажи нападают на все что движется! Давайте научим их защищаться:

//
// proSwift.ru
//

class DefenceStrategy: BasicStrategy {
    
    func actionPerson1() {
        print("Герой 1 - атакуй всех врагов")
    }
    
    func actionPerson2() {
        print("Герой 2 - Лечи героя 1")
    }
    
    func actionPerson3() {
        print("Герой 3 - защищай героя 2")
    }
}

Во время защитной стратегии, наши персонажи действуют по-другому – кто атакует, кто лечит, а некоторый даже защищают:) Ну, теперь как-то надо это все использовать. Давайте создадим нашего игрока:

//
// proSwift.ru
//

class Player {
    var strategy: BasicStrategy
    
    func makeAction() {
        self.strategy.actionPerson1()
        self.strategy.actionPerson2()
        self.strategy.actionPerson3()
    }
    
    func changeStrategy(aStrategy: BasicStrategy) {
        self.strategy = aStrategy
    }
    
    init(strategy: BasicStrategy) {
        self.strategy = strategy
    }
}<br>

Наш игрок может только менять стратегию и действовать в зависимости от этой стратегии. Код для тестирования:

//
// proSwift.ru
//

let a = AttackStrategy()
let d = DefenceStrategy()

let p = Player(strategy: a)
p.makeAction()
print("- - - - - - -")
p.changeStrategy(d)
p.makeAction()

Вывод лога в консоль:

Герой 1 - атакуй всех врагов
Герой 2 - атакуй всех врагов
Герой 3 - атакуй всех врагов
- - - - - - -
Герой 1 - атакуй всех врагов
Герой 2 - Лечи героя 1
Герой 3 - защищай героя 2

Пример с GitHub

Шаблон «Стратегия» используется для создания сменного семейства алгоритмов, из которых нужный процесс выбирается во время выполнения.

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

protocol PrintStrategy {
    func printString(string: String) -> String
}

class Printer {
    
    let strategy: PrintStrategy
    
    func startPrinting(string: String) -> String {
        return self.strategy.printString(string)
    }
    
    init(strategy: PrintStrategy) {
        self.strategy = strategy
    }
}

class UpperCaseStrategy : PrintStrategy {
    func printString(string:String) -> String {
        return string.uppercaseString
    }
}

class LowerCaseStrategy : PrintStrategy {
    func printString(string:String) -> String {
        return string.lowercaseString
    }
}


var lower = Printer(strategy:LowerCaseStrategy())
let str1 = lower.startPrinting("O tempora, o mores!")
print(str1)

print("- - - - - - - - - -")

var upper = Printer(strategy:UpperCaseStrategy())
let str2 = upper.startPrinting("O tempora, o mores!")
print(str2)

Для принтера, который умеет печатать строки, мы создаем две стратегии: печать строчными и заглавными буквами. Подменяя стратегии у экземпляра принтера, мы меняем строку вывода.

o tempora, o mores!
- - - - - - - - - -
O TEMPORA, O MORES!


Метки:

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

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

*

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