Как часто бывает, я однажды зашел в Google, чтобы напомнить себе о некоторых важных программных штуках, которые когда-то в моем мозгу и с тех пор выпали по пути.

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

«Да!», - подумал я, - «Фабрика по их выпуску будет очень хорошо работать».

Фабрика создает экран и настраивает переменные биты. Все, что я делаю, это говорю ему, чего пытаюсь достичь, и он возвращает мне конкретную цель.

Шаблон фабричного метода - мощный, полезный и прекрасно расширяемый. Он скрывает скучную инстанциацию и настройку, делая ваш код более понятным; меньше шаблонной ерунды, скрывающей свое истинное предназначение.

Если ты делаешь это правильно.

Путешествуя по Интернету, чтобы напомнить себе обо всех тонкостях, я наткнулся на следующий (слегка отредактированный) код с учебного веб-сайта.

Я просто испытываю сильные чувства по поводу этого и многих способов, которыми это нарушает Хороший Кодекс.

Принцип открытого / закрытого

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

Необходимо изменить реализацию getCoffee(String coffeeType). Кто знает, какие ужасы ждут, какие ошибки будут внесены, какие изменения сигнатуры методов могут потребоваться? Такие мысли не дают мне уснуть по ночам.

Решение? getEspresso(), getRistretto(), getLatte().

Таким образом, любые дополнения (getReallyFancyCoffee()) расширяют класс. Интерфейс остальной части приложения не меняется. Код для создания латте не будет случайно предан забвению. Все намного счастливее.

Управление связью

Передавая «ESPRESSO», вызывающему классу открывается глубокое знание внутренней работы метода, что обеспечивает тесную связь вызывающего класса не только с вызываемым классом, но и с его фактической реализацией.

Рассмотрим внутреннее обновление, чтобы удалить «PUMPKIN_SPICE_SPECIAL», поскольку мы приближаемся к концу осени и направляемся в сезон «PEPPERMINT_SNOW_SPECIAL».

Каждый отдельный класс, модуль, клиент, которому нужен особый напиток, необходимо обновить. Вы их все определенно обновили? Ваши клиенты определенно обновили их все?

Решение? См. Выше - расширение, а не изменение, чтобы скрыть эти внутренние детали.

Строки

Если вам абсолютно необходимо передать какие-то данные, сделайте все возможное, чтобы не использовать String. Струны невыразительны и небезопасны; Компиляторы не исправляют ошибок, которые приводят к неприятным ошибкам в технически правильном, но функционально некорректном коде.

Опечатка getCoffee(“TEA”) вернет ноль 😣

Невыразительный характер String в сочетании с непомеченными аргументами приводит к пагубным ошибкам, таким как getCoffeeWithSyrup(“CARAMEL”, “FILTER”) вызов getCoffeeWithSyrup(String coffee, String syrup) 😖

И, чтобы мы не забыли о нашем обучении безопасности, getCoffee(“L33T_HAX0R_SCRIPT”) вырубит всю базу данных и обанкротит компанию 😫

Мы можем выявить подобные ошибки при тестировании, но мы должны использовать все доступные механизмы безопасности.

Решение?

  • Используйте Enum в языках, где они являются типами значений; дешево создавать и разрушать. getCoffee(Coffee coffee), getCoffeeWithSyrup(Coffee coffee, Syrup syrup) выразительны и безопасны по типу.
  • Используйте решения для конкретных платформ, такие как Android IntDef, где Enum - мусор, занимающий много памяти.
  • Используйте Enum там, где у вас нет другого выхода, потому что, по крайней мере, он лучше, чем String

Шаблон «Заводской метод»

Последняя капля? На самом деле это не шаблон заводского метода. 😱

Гораздо более умные люди, чем я, рассказал об этом подробно, но вкратце -

  1. Определите интерфейсы для получения напитка Coffee из CoffeeFactory.

2. Напишите их конкретные реализации.

3. Выберите правильную фабрику, помня о других моментах этого блога, позвоните getCoffee() и наслаждайтесь сладким, сладким вкусом успеха.

И кофе. ☕️

Обе реализации CoffeeShop приемлемы; на то, что работает в конкретной кодовой базе, повлияют не только соображения чистого кода. Это баланс - поддерживаемый, расширяемый, ясный, краткий, эффективный, YAGNI, и фактически доставляющий продукт пользователям.

Шаблоны дизайна - бесценный инструмент в этом отношении, предлагая хорошо понятные решения типичных проблем ... если мы используем их правильно и не злоупотребляем ими.

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

  1. Невозможно следовать каждой хорошей кодовой практике. Не пытаться. Так лежит безумие. Всегда будет требоваться компромисс из-за факторов, находящихся вне вашего контроля. Некоторые практики даже противоречат друг другу. Все, на что мы можем надеяться и к чему стремиться, - это код, который будет настолько читабельным, поддерживаемым и расширяемым, насколько мы можем его сделать.

2. Как и выше, невозможно каждый раз быть идеальным.