Java 8 vs GoF: Strategy

Продолжаем наш батл между Java 8 и бандой четырех. Сегодня под колеса новых возможностей православной Java попал паттерн “Стратегия”. Но не будем спешить и для начала вспомним о чем вообще данный шаблон проектирования. Стратегия - поведенческий паттерн, задачей которого является определение и инкапсуляция группы алгоритмов, а также обеспечение их взаимозаменяемости. Это позволяет нам менять реализацию поведения на лету. Освежим в нашей памяти UML-диаграмму данного шаблона.


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

Вполне годится. Сперва реализуем сравнение строк по их длине.

А еще мы будем сравнивать их по первому символу.

Теперь осталось запедалить сортировщик (Context), которым смогут пользоваться наши пользователи.

Ничего военного. Давай проверим все ли правильно работает.

Похоже на правду. А теперь подумаем, как мы можем усовершенствовать реализацию данного паттерна используя фишки Java 8. По сути оба наших класса StringLengthComparator и FirstLetterComparator нужны только для того, чтобы инкапсулировать в себе некое поведение. То есть, как и в прошлый раз, их можно заменить на лямбды. Тем более, что интерфейс Comparable как раз является функциональным, о чем даже говорит аннотация @FunctionalInterface. Но погодите ка! А почему тогда мы видим в интерфейсе два абстрактных метода? Разве метод equals не мешает ему быть функциональным? Ответ кроется в официальной документации:

If an interface declares an abstract method overriding one of the public methods of java.lang.Object, that also does not count toward the interface's abstract method count since any implementation of the interface will have an implementation from java.lang.Object or elsewhere.

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

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

Как и в прошлый раз мы избавились от стереотипного кода, сделали наше приложение немного проще и понятнее.

P. S. Полезные материалы: как обычно это доклад Николая Алименкова The modern view on classic design patterns, а также его примеры новых реализаций паттернов на GitHub.

Comments

Popular posts from this blog

JEEConf 2017 How it was

Separate and rule your tests