Why patterns?
Каждый разработчик после того, как освоит базовые и даже продвинутые техники ООП языка, сталкивается с проблемой архитектурного оформления кода. Зачем архитектура ? Неизбежно с развитием приложения растёт и его сложность. Нужно делать реализацию новых фичей так, чтобы она была масштабируемой т.е чтобы новый код было легко расширять.
В этом нам и помогут паттерны.

Ядро всех паттернов
В основе почти всех паттернов лежит простая концепция:
Изменение некоторой части системы должно быть независимо от других частей, не должно влиять на другие части системы
Эту концепция можно выразить иначе:
Выделите переменные состявляющие, аспекты приложения,которые могут изменяться, и отделите, инкапсулируйте их, чтобы позднее их можно было изменять или расширять без воздействия на постоянные составляющие.
Имитатор утиного пруда
Разберем следующий пример. Есть игра - утиный пруд, в котором плавают и крякают утки рахных видов.
3 - лаконично поддержать новое поведение “утки летают”.
Первая мысль
о том как пожжержать подобное решение , будет что-то вродe

Однако данная реализация чревата пустыми методами, т.е непереопреденными. В итоге код будет избыточным.
Действительно,зачем наделять класс DecoyDuck() функциональностью, который он никогда не будет реализовывать.Деревянная уточка никгда не будет крякать.
Вторая мысль
Будет такая. а что если отказаться от одного общего класса в угоду нескольким интерфейсам и тогда наделить тот или иной Утиный класс соответсв. набором интерфейсов. Примерно так:

Однако тут мы сталкиваемся со следующей проблемой -
эти интфейсы,нужно реализовывать каждый раз. и Нельзя сохранить и переиспользовать реализацию интефейса,т.е сохранить поведение.
Каждый раз,когда встречаешь набор различных поведений, которые реализуют некий контракт и разница между ними лишь в реализации этого контракта - знай, перед тобой Паттерн Стратегия
Собственно, разные поведения - это разные стратегии.
Отделяем переменное от постоянного
Абстрактно, это будет выглядеть так:

Проектирование переменного поведения
Требования у реализации такие:
- Инициализация
*Duckс конкретным типом поведенияfly() - Runtime изменение поведения полета или крякания утки.
Принцип проектирования:
Программируйте на уровне интерфейсов, а не уровне реализации.
Таким образом , аспект поведения, т.е контракт поведения будет задаваться через interface, а конкретная реализация - через class, но фишка в том,что это будет класс отдельный , не класс Duck.
Duck не нужно знать подробности реализации своих аспектов поведения. Поведение будет инкасулировано от Duck в отдельных реализациях контракта данного поведения.

Интеграция поведения с классом Duck
Класс Duck теперь делегирует свои аспекты поведения(вместо простого использования методов,определенных в классе Duck или его субклассах)
-
Сначала в класс Duck включаются две переменные экземпляров flyBehaviour and quackBehaviour, обьявленные с типом интерфейса. На стадии инициализации присваеваем конкретную реализацию поведения.
-
Делегирование поведения - крякания и полета - в класс утка в perform методы: performQuack, performFly. т.е Именно в них будут вызываться методы делегированного поведения. Звучит пространно, поэтому приведем код.
public class Duck{
QuackBehaviour quackBehaviour;
public void performQuack(){
quackBehaviour.quack();
}
}
Приведем теперь полную реализацию на kotlin.
Inheritance vs composition
Каждая утка СОДЕРЖИТ экземпляры FlyBehaviour и QuackBehaviour, которым делегируется выполнение соотв. операций. Это механизм композиции. Поведение не наследуется, а предоставляется правильно выбранным обьектом.
Еще 1 преимущество перед наследованием : можно изменять поведение в runtime. Динамически.
Принцип проектирования : отдавайте предпочтение композиции перед наследованием.
Final Definition of Stratehy Pattern
Паттерн Стратегия определяет семейство алгоритмов, инкапсулирует каждый из них и обеспечивает их взаимозаменяемость. Он позволяет модифициовать алгоритмы независимо от их использования на стороне клиента.
Bonus : Kingdom people strategies

