1. Java / Говнокод #27360

    +2

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    19. 19
    20. 20
    21. 21
    22. 22
    23. 23
    24. 24
    25. 25
    26. 26
    27. 27
    28. 28
    29. 29
    30. 30
    31. 31
    32. 32
    33. 33
    34. 34
    35. 35
    36. 36
    37. 37
    38. 38
    39. 39
    40. 40
    41. 41
    42. 42
    43. 43
    44. 44
    45. 45
    46. 46
    47. 47
    48. 48
    49. 49
    50. 50
    51. 51
    52. 52
    53. 53
    54. 54
    55. 55
    56. 56
    57. 57
    58. 58
    59. 59
    60. 60
    61. 61
    62. 62
    63. 63
    64. 64
    65. 65
    66. 66
    67. 67
    package org.trishinfotech.builder;
    
    public class Car {
    
        private String chassis;
        private String body;
        private String paint;
        private String interior;
        
        public Car() {
            super();
        }
    
        public Car(String chassis, String body, String paint, String interior) {
            this();
            this.chassis = chassis;
            this.body = body;
            this.paint = paint;
            this.interior = interior;
        }
    
        public String getChassis() {
            return chassis;
        }
    
    	public void setChassis(String chassis) {
            this.chassis = chassis;
    
        }
    
        public String getBody() {
            return body;
        }
    
        public void setBody(String body) {
            this.body = body;
        }
    
        public String getPaint() {
            return paint;
        }
    
        public void setPaint(String paint) {
            this.paint = paint;
        }
    		public String getInterior() {
            return interior;
        }
    
        public void setInterior(String interior) {
            this.interior = interior;
        }
    
        public boolean doQualityCheck() {
            return (chassis != null && !chassis.trim().isEmpty()) && (body != null && !body.trim().isEmpty())
                    && (paint != null && !paint.trim().isEmpty()) && (interior != null && !interior.trim().isEmpty());
        }
    
        @Override
        public String toString() {
            // StringBuilder class also uses Builder Design Pattern with implementation of java.lang.Appendable interface
            StringBuilder builder = new StringBuilder();
            builder.append("Car [chassis=").append(chassis).append(", body=").append(body).append(", paint=").append(paint)
            return builder.toString();
        }
    
    }

    https://habr.com/ru/company/otus/blog/552412/
    Паттерн проектирования Builder (Строитель) в Java

    Запостил: PolinaAksenova, 15 Апреля 2021

    Комментарии (109) RSS

    • Если нячинающие джависты обучаются ня таких примерах — что удивительного в том, что няписание короткого и ёмкого кода становится для них сродни пытке?
      Ответить
      • По Java есть книжка, что-то про рефакторинг и идеальный код, в котором есть просто УЖАСНЫЕ примеры. Ну, мы её с хабра притаскивали и гыгыкали.
        Ответить
      • Не знаю что там у джавистов, но я у себя для микроконтроллеров такую хуйню не пишу.
        Ответить
        • Да, у тебя это будет просто структура на 4 строчки.
          Ответить
      • Самый ужас, это когда начинающие С++ники пытаются изобразить декоратор.
        Ответить
    • https://youtu.be/15hQ-7L2Q9A

      Вот такой это builder.

      Вообще, мне кажется, что как в некоторых числовых последовательностях закладывается избыточность для выявления очепяток, так и в йаже введён специфический избыточный синтаксис с гротескными и гипертрофированными паттернами, чтобы даже САМЫЙ тупой джавист мог писать код с минимальным количеством ошибок.
      Ответить
    • А где здесь билдер? Обычный бройлерплейт с гетерами и сеттерами.
      Ответить
    • Доброе утро, PolinaAksenova.
      Паттерн билдер вроде же должен иметь метод `build()', возвращающий инстанс другого класса.
      Ответить
      • А, я нашла! В строке 62 есть билдер.
        Ответить
      • > StringBuilder builder

        Вот твой билбер.

        А класс выше – это так, бойлерплейт для этого билбера.
        Ответить
      • Ня!
        Весь простенький пример паттерня Строитель в той статье состоит из 283 строк. Ня влез ≡(▔﹏▔)≡.
        Ответить
        • Ух ты, быстро дочитала статью про джаву с примерами, и шести часов не прошло!
          Ответить
        • Кстати, почему паттерны всегда объясняют на каких-то тривиальных примерах, где они нафиг не сдались?

          Никто не хочет приводить реальный пример системы, в которой применение паттерна помогло сделать код понятнее. Ссылку на какую-нибудь репу, где это реально юзается, к примеру.
          Ответить
          • > Никто не может приводить реальный пример

            Поправил. Потому что в вузе нам преподавали ТРИЗ, тот самый, в котором лучшая система та, которой нет. Именно поэтому я не пользуюсь паттернами, а просто дописываю питушню в funkcii.php и теку, значит паттерны не нужны!
            Ответить
          • Ещё бесит что когда люди пишут багрепорты к библиотеке там какие-то ебанутые и вырожденные примеры

            Пусть кинут ссылку на какую-нибудь нибудь реальную репу где баг воспроизводится
            Ответить
            • 90% случаев — баг в проприетарщиене, которую без согласования со спортлото в нормальном объёме не покажешь.
              10% — Issue закрыт с причиной "хз, вроде всё нормально, баг где-то у вас" или "я ебал настраивать билд систему для вашего проекта и собирать его, чтобы проверить существование бага."
              Ответить
          • У GoF вроде в начале книги было описание рахитектуры текстового редактора с использованием паттернов.

            Проблема в том, что код нужно комментировать, место в книге денег стоит, а кидать ссылку на репу — свинство по отношению к тем, кто решил почитать книгу, пересекая Тихий океан.
            Ответить
            • для этого есть inmarsat
              но дело не в этом, если вербозность не влезает в книгу, то такая книга нахуй не нужна
              всякие приложения к книге не должны становиться неотъемлемой частью
              Ответить
          • Потому что изучать паттерн проще на простом примере, не тратя время на вникание в чужой код.
            Ответить
            • > изучать паттерн проще

              Ок, принято. А как понять, когда я реально его должен юзать?

              З.Ы. Я не утверждаю, что простые примеры надо выбросить. Я утверждаю, что надо дополнять их реальными примерами, где можно вникнуть в чужой код и увидеть паттерн на практике.
              Ответить
              • ну, про это можно написать отдельно.

                Нужно конечно и то, и то: и пример кода (который умещается на один экран) и реальный пример.
                Ответить
                • > написать отдельно

                  Да не напишешь ты это словами... Так потом и рождаются джависты, которые срут паттернами и лепят из них архитектуру, не понимая зачем они это делают.
                  Ответить
                  • так нет, можно и кодом показать, но это нужно делать параллельно.

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

                    Если я хочу быстро узнать патттерн, то мне нет смысла вникать в проект: я обычно уже и так понимаю зачем мне паттерн нужен. А если я изучаю его с ноля, то да, нужно показывать реальный пример.
                    Ответить
                    • Х.з., я бы вот лучше реальные примеры покурил чтобы прочувствовать пользу от паттерна и увидеть, как красиво он встроен в код. Это особо много времени не займёт если автор указал на все интересные моменты.
                      Ответить
                • З.Ы. Ну вот зачем, к примеру, автор статьи рассказывает об иммутабельном Employee и билдере для него? Какую задачу ему поможет решить эта иммутабельность. В джаве.

                  Я ещё ни в одной статье не видела внятного ответа на вопрос "а нахуя?"
                  Ответить
                  • ну вообще билдер позволяет разнести код сборки объекта в разные места, но при этом сохранить иммутабельность, которая гарантирует тебе некоторый инвариант класса (иначе ты будешь постоянно не понимать в каком он состоянии)
                    Ответить
                    • Employee с зарплатой и текущим проектом очень хороший кандидат на иммутабельность, конечно... В госконторе работает, видимо.
                      Ответить
                      • кто угодно хороший кандидат, если он живет пять секунд (например в рамках обработки http запроса)
                        Ответить
          • Именно поэтому я долго не мог въехать в посетителя
            Ответить
            • > посетителя

              Нинужный костыль для убогих оопшных язычков, которые умеют диспатчить только по первому аргументу.
              Ответить
              • Действительно, если можно было бы диспатчить по типу аргумента в рантайме (а не только по типу объекта, сиречь первого аргумента) то визитор был бы не нужен, но только если твой язык не статически типизирован, бо визитор заставляет тебя обработать ВСЕ возможные типы, а в скриптушне это не нужно.

                Хорошая альтернатива визитору это pattern matching с exhausted when + sealed classed в коко
                Ответить
              • А как же всяческая SAXня?
                Ответить
                • Паттерн-матчинг? Ну серьёзно, зачем городить ООП в задаче, где хватает обычного свича.
                  Ответить
                  • Для маленьких штук — возможня. А большие всё равно превратятся в какое-нябудь
                    parse_node(node):
                        match(node):
                            NodeFoo: parse_foo(node)
                            NodeBar: parse_bar(node)
                            NodeNya: parse_nya(node)
                    Ответить
    • > public String getChassis() {

      Давайте угадывать кто и как оскорбился на слово «Wheel».
      Ответить
      • А ещё у него краска на машине остаётся даже после замены кузова... ООП отлично отражает реальность.
        Ответить
      • А вдруг там гусеницы? Полугусеницы? Шасси от Бостон Динамикс? Воздушная подушка?
        Ответить
    • Как написать 66 строк ни о чем: мастер класс.

      Напоминает дешевые SEO тексты:

      "Как покрасить стену?
      Безусловно, каждому из нас рано или поздно приходится сталкиваться с вопросом: как покрасить стену?
      Чтобы ответит на такой важный вопрос, как покрасить стену, предлагается прочитать вот эту статью, которая кстати так и накзывается: как покрасить стену"
      Ответить
    • и это хуевый билдер кстати, бо настоящий должен возвращать this, чтобы писать

      petuh.setIq(-1).setName("dzhavist")
      Ответить
      • Дык это не билдер. Билдер ниже по коду подразумевается. И он this возвращает.
        Ответить
    • переписал на С++, проверь
      #include <iostream>
      #include <memory>
      
      struct Employee {
              int age;
              int salary;
      };
      
      std::shared_ptr<const Employee> build() {
              auto employee  = std::make_shared<Employee>();
              employee->age = 99;
              employee->salary = 100;
              return employee;
      }
      
      
      int main() {
              auto  employee = build();
              std::cout << employee->age << std::endl;
              //employee->age = 100; //объект уже собран
      
      }
      Ответить
      • // почему не просто
        auto employee = std::make_shared<Employee>(99, 100);
        Ответить
        • Чтобы джавных приманить на звук тыканья клавиш.
          Ответить
        • Потому что тогда теряется смысл билдинга
          между строками
          employee->age = 99;
          и
          employee->salary = 100;

          может быть куча кода!
          Ответить
          • > куча кода

            Типа

            employee->salary = 25;
            return;

            ?
            Ответить
            • if (sorokoTysachObezjan()) {
              employee->salary = doAll();
              } else {
              employee->age = 122;
              employee->salary = doAll(foo=Bar);
              }


              любая логика
              Ответить
          • int age = 99;
            // много кода
            int salary = 100;
            auto employee = std::make_shared<const Employee>(age, salary);
            Билдеры какие-то... Именно поэтому я и писал про реальные примеры.
            Ответить
            • Это если ты не обращаешься к employee там, где много кода.
              Ответить
              • А как ты к нему будешь обращаться, если согласно паттерну в этом месте у тебя нет его инстанса, а есть только билдер?
                Ответить
                • Значит тогда это если ты не обращаешься к билдеру.

                  Например:

                  r = request.addDetail("koko")
                  if (len == 1):
                  . . . . r.addDetail("ololo").fire()
                  else:
                  . . . . r.removeDetail("defolt").addCode(200).fi re()
                  Ответить
                  • Ну вот это ближе к практике... Здесь билдер содержит в себе удобные и осмысленные методы для настройки состояния. А не просто ебучий бесполезный setField() для каждого поля.
                    Ответить
                    • А вообще билдер – это джавный костыль, потому что у них строки иммутабельные лол )))
                      Ответить
                      • > джавный костыль

                        Да не, вот например какой-нибудь построитель запросов -- хороший, годный пример билдера.

                        Я пишу что-то в духе query.where(employee.name, "bormand").all() и мне пофиг, как билдер это будет переводить на конкретный диалект "SQL" (или даже "NoSQL").

                        Вот оно, то самое разделение между "что построить" и "как построить".
                        Ответить
                        • Ещё билдер можно передавать между функциями. Передал в какой-нибудь модуль, там навешали, что им надо, а ты потом у себя вызвал build и радуешься.
                          Ответить
                          • Поздравляю, вы изобрели фабрику!
                            Ответить
                            • У GoF нету паттерна "фабрика": есть "фабричный метод" и "абстрактная фабрика" емнип (15 лет назад читал последний раз)
                              Ответить
                              • А я не читал такую книжку, поэтому не знал. Надо будет почитать :-)
                                Ответить
                              • > 15 лет назад читал последний раз

                                На собеседованиях уже никто не спрашивает?
                                Ответить
                                • Давно не менял работу)
                                  Но перед собеседами я обычно тренировал алгоритмы, их сложнее вспомнить, чем паттрены. Правда все равно ничего слоднее qsort и binary search на обычных работах не спрашивают
                                  Ответить
                                  • А если это не обычная работа, а, допустим, web design?
                                    Ответить
                                    • Я никогда не работал веб-дизайнером:)
                                      Мое представление о дизайне примерно на уровне вот

                                      https://butaji.files.wordpress.com/2009/03/d180d183d0bad0bed0b2d0bed0b4d181d182d0b2d0be-d0bfd0be-ui-d0b4d0b8d0b7d0b0d0b9d0bdd183-d0b4d0bbd18f-d0bfd180d0bed0b3d180d0b0d0bcd0bcd0b8.pdf
                                      Ответить
                                  • > binary search

                                    Напишешь с первого раза, нигде не залетев на единичку и не соснув UB'ца?
                                    Ответить
                                    • Вполне вероятно, что обосрусь на единицу, но перед собеседованием напишу его несколько раз, и тогда не обосрусь.

                                      Но не всегда просят писать: иногда просто нужно рассказать какие есть виды поиска, какие у них требования к данным, и какие большие О
                                      Ответить
                                      • Ну и какое большое О у куиксорта? )))
                                        Ответить
                                        • лохорифмическое вроде

                                          оно, кстати, зависит от сортированности говна изначально
                                          Ответить
                                          • Даа, так что О большое – n^2, омега – nlogn, а вот тета – nlogn, вроде бы так...
                                            Ответить
                                            • > О большое – n^2
                                              это худшее же. Его можно шафлнуть, чтобы такого говна не получить вроде (если не путаю)
                                              Ответить
                                              • Лучше не шаффлить, а делать рандомизированное разбиение вокруг опорного элемента.
                                                Ответить
                                                • Сразу видно, что ты к собесу готовишься)
                                                  А про сортировку слиянием помнишь?
                                                  Ответить
                                                  • MergeSort всегда выдаёт nlogn, при этом в лучшем случае qsort будет быстрее, но и мердж может быть быстрее кусорта!
                                                    Ответить
                                                    • правильно приготовленный qsort вроде как почти всегда будет шустрее, но он не конюшня. иногда это может быть важно.

                                                      В частности в джаве для примитивов ку, а для объектов был merge, но теперь там есть еще TimSort.
                                                      Ответить
                                                      • Кстати, Рафгарден про стабильность ничуво не пишет (((
                                                        Ответить
                                    • non-binary search
                                      Ответить
                            • Фабрика всё же специализируется на создании объекта исходя из заданных параметров. А Builder скорее про создание объекта кусками.
                              Ответить
                              • Да, это правда. Просто передача билдера в функцию – очень похожа на фабричный метод. С другой стороны, можно передавать билдер в несколько функций, а это уже будет похоже на декоратор либо на интерфейсы...
                                Ответить
                                • Ня?
                                  def filter_able_bodied(query, table):
                                      return query.where(table.age >= 18).where(table.age < 65)
                                  
                                  
                                  q = query(User).where(User.country == Countries.RU)
                                  q = filter_able_bodied(q, User)  # Тут ( •̀ ω •́ )✧
                                  q = q.order_by(User.age)
                                  # ...
                                  users = q.all()
                                  Ответить
                                  • >(User.country == Countries.RU
                                    как эта хрень работает?

                                    там как-то оператор == перегружен и чото такое возвращает?
                                    Ответить
                                    • User.country — объект типа Column. У Column перегружен __eq__(self, other), который возвращает какую-то штуковину, которая потом в SQL выплёвывает равенство.
                                      Да.
                                      Ответить
                                      • какая алхимия ))

                                        В джанге это более попидарски, типа

                                        where(user__contry_eq=Countries.RU)
                                        Ответить
                                        • Какое-то не ня. Колонка переименуется — искать все вхождения будет весело.
                                          Ответить
                                          • У джанги вообще отсосный ORM по сравнению с SQLAlchemy, это все признают

                                            Кстати, ты умеешь пользоваться гибридными атрибутами в SQLAlchemy?

                                            Это, имхо, самая киллер фича по сравнению с джангой
                                            Ответить
            • >int age = 99;
              если у тебя таких полей 22, то ты будешь 22 поля копипастить?
              Ответить
              • А сам билдер -- это уже не копипаста 22 полей? ;)
                Ответить
                • В примере с С++ нет, не паста.

                  В примере с джавой -- паста. Правда это паста в ОДНОМ месте, а не во всех местах использования.

                  Алсо, см пример емейлпротектда с передачей билдера
                  Ответить
                  • В твоём примере с с++ это вообще не билдер, имхо. Отдельной сущности же нету, просто заморозка объекта после инициализации.
                    Ответить
                    • Однако же решается главная задача: некую сущность удобно собрать по кусочкам, и потом сделать иммутабельной

                      Вот если бы там в структуре были какие-то методы, то да: без отдельного билдера бы не получилось, пушо пока билд не закончен объект не консистентен, и методы вызвать нельзя
                      Ответить
    • Pokolenie zadrotov
      https://twitter.com/Jetskigrizzly/status/1382712270677942276
      Ответить
      • ты давно тестостерон мерял?
        Ответить
        • Недавно.
          Ответить
          • носочки еще не нужны?
            Ответить
            • Кэмп, если у меня Subject в rxjs получает события ДО того, как к нему присоединились обсерверы, и я хочу, чтобы они получили всё говно, что было до них, то мне подойдет ReplaySubject?
              Ответить
              • в теории да

                на практике получение произвольного кол-ва данных из прошлого обсера звучит сомнительно
                Ответить
                • А у тебя никогда не бывает, что кто-то насрал событиями раньше, чем подключился первый слушатель? Городить свой буфер как-то не охото

                  Правда конечно нужно гарантировать, что он подключится, иначе там буфер раздуется

                  Хотя.. он же навсегда закеширует ВСЕ данные?
                  Ответить
                  • Там аргумент в конструкторе сколько надо

                    Но чтобы нужно было хранить стейт обсервера между подключениями не припомню, разве что для расширения хрома где хуй знает когда что на страницу подгрузится
                    Ответить
    • https://twitter.com/sorrysunshine25/status/1366340962742652934
      Ответить
      • Однажды хотел исправить 2/3 на 1/3, а написал почему-то 2/1. Но самое гнусное, что железяка работала, только нестабильно и не во всех режимах (там значение из-за переполнения байта не слишком отличающееся получилось). Пока не догадался частоту осциллографом померить, все мучился со всякой защитой от помех, поиском закономерностей и т.п..
        Ответить
    • ааааааааааааа
      https://caizcoin.com/
      Ответить
    • В каком месте это паттерн билдер?
      Ответить
    • Почему Java ня нужна? Потому что:
      class Car(
          var chassis: String?,
          var body: String?,
          var paint: String?,
          var interior: String?
      ) {
          constructor() : this(null, null, null, null)
      
          fun doQualityCheck() = arrayOf(chassis, body, paint, interior).all { !it.isNullOrBlank() }
          override fun toString() = "Car [chassis=$chassis, body=$body, paint=$paint]"
      }

      Можня было ня писать лишний конструктор, а проставить default-аргументы (Котлин бы сам сгенерировал отдельный Car(), кстати), но оригинал ня мог принимать ня все параметры, так что и мы ня будем.

      В оригиняле, кстати, автор так вдохновился крутым "Builder Design Pattern" в toString(), что забыл поставить закрывающую квадратную скобку: видимо, от количества бойлерплейта, которого ему пришлось написать, мозг нямножко разжижился.
      Ответить
      • Это не билдер всё таки. Я бы не хотел иметь класс у которого половина полей не установлена
        Не хотел бы иметь возможность вызывать его методы
        Ответить
        • Это точный перевод оригиняльного класса. Билдер там ещё через пару сотен строк "кода".

          Но да, без nullable этот класс в Котлине будет ещё няшнее.
          Ответить
          • ну ни на джаве ни на коко это красиво не сделать, увы

            А на TS сделать (как и на крестах)
            class Car {
                public chassis?: string
                public body?: string
            
                build(): Readonly<NonNullable<Car>> { //убираем вопросики и делаем иммутабельными
                    Object.keys(this).forEach((field) => {
                        if (!field) {
                            throw new Error(`Field ${field} is not set`);
                        }
                    });
                    return this; //Можно еще Object.freeze
                }
            }
            Ответить
            • А ещё на коко (который пипи) можно красиво сделать. Только я не знаю как...
              Ответить

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