Ответы пользователя по тегу ООП
  • Как правильно распределять ответственность между классами?

    DollyPapper
    @DollyPapper
    Про репозиторий можно почитать например тут
    Ответ написан
    Комментировать
  • Является ли чтение Readonly свойств объекта нарушением инкапсуляции?

    DollyPapper
    @DollyPapper
    Вы путаете инкапсуляцию и сокрытие информации. Инкапсуляция это логическое объединение взаимосвязанных логических едениц в одной сущности. Т.е. методы и поля объекта объединяются в одном классе. Это и есть инкапсуляция. А есть такое понятие как сокрытие информации. Это не только про обращение к закрытым полям класса, это вообще про ракскрытие внутренней структуры нашего объекта для внешнего пользователя. Например если мы создаём юзера который в конструкторе принимает id как целое число, это нарушение сокрытия информации, т.к. внешний по отношению к обьекту пользователь знает, что технически внутри наш id это целое число, и например захочет его инкрементировать, а мы не хотим чтобы так было.
    Ответ написан
    3 комментария
  • Зачем паттерн одиночка?

    DollyPapper
    @DollyPapper
    Разница в том, что одичка создает объект который доступен в единственном экземпляре в системе. А статические классы это не объекты, это классы.
    Ответ написан
    Комментировать
  • Как использовать классы через интерфейсы?

    DollyPapper
    @DollyPapper
    Суть в том, что как вы и сказали: интерфейс это контракт. Можно его еще назвать "тип". Т.е. завязываясь на интерфейс мы обязуем вызывающий код передать нам штуку которая умеет делать определенный список вещей. Собственно все. Немного не правильно противопоставлять интерфейсы наследованию. Наследование это когда одна штука является спицифичной версией другой штуки. Интерфейс же в свою очередь это больше клиентская часть, когда код говорит - я хочу на вход переметр такого-то типа. Давайте простой высосаный из пальца, но довольно ясный пример:
    Есть класс Parser
    class Parser
    {
    	public function getPage($url){
    		return $this->load($url);
    	}
    	protected function load($url){
    		return file_get_contents($url);
    	}
    }

    Есть класс Exchanger
    class Exchanger extends Parser
    {
    	public function getRate($currency){
    		return $this->load('...?id=' . $currency);
    	}
    }

    В примере выше в классе Exchanger мы унаследовали метод load из базового класса. Дальше используем
    $parser = new Parser();
    $parser->getPage('...');
    
    $exchanger = new Exchanger();
    $exchanger->getRate('USD');

    Т.е. и там и там должен быть метод load который по http что-то откуда-то грузит и выдает данные которые дальше как-то используются и т.к. метод load уже есть в классе Parser, ну мы просто унаследовали его и все работает. Но при таком подходе появляются проблемы. Не понятно по какому принципу вообще Exchanger наследуется от Parser, это два семантически друг с другом не связанных класса. И почему у Exchanger есть метод getPage тоже не ясно. Можно пойти по другому. Сделать отдельный класс Loader с методом load и оба унаследовать от него. Это в целом тоже задачу решает, но если появится еще специфичная функциональность которую могут использовать оба наших класса? Множественного наследования нет. Добавлять эту функциональность в Loader? Опять же нарушится консистентность нашего Loader. Можно пойти третим путем. Сделать интерфейс Loader и указать что Parser и Exchanger требуют в качестве зависимости что-то, что имеет метод load. В этом случае нет проблем описанных выше, и есть доп. плюшки, например упрощается тестирование, потому что можно будет вместо обьекта который реально лезет куда-то по http передать заглушку которая просто в методе load возвращает готовые данные.
    Ответ написан
    Комментировать
  • Где можно найти задачи для практики ООП?

    DollyPapper
    @DollyPapper
    Сама поставновка вопроса говорит о том, что никуда вы в этом плане не продвинулись. Посмотрите курс "Дмитрий Елисеев - Неделя ООП". Там примеры на PHP, но это не должно пугать, т.к. в ООП платформозависимое по сути только наследование, и то, синтаксически во всех С-подобных языках оно +- одинаковое.
    Ответ написан
    Комментировать
  • Может кто-нибудь дать реальную задачу на которой можно применить ООП?

    DollyPapper
    @DollyPapper
    В том беда современного обучения программированию, что учат ООП на наследовании кошечек и собачек от абстрактных животных, а нахера это делать и зачем это появилось не учат. Плохая для вас новость - вы не поймете прелести подхода пока не проработаете хотя бы годик на реальном проекте. Но понять сам ООП вы можете не работая. Попытаюсь натолкнуть вас на мысль, и обьяснить истоки, откуда пошло ООП и зачем, через какое-то время вы осознаете эти концепции. Итак.
    Когда мы пишем программу, мы так или иначе моделируем какую-то часть реальности. Модель это несовершенное представление самой этой реальности, с выделенными атрибутами необходимыми для нашей решаемой задачи (абстрагирование, один из принципов ООП), например детская игрушка самолет, это модель реального самолета который копирует лишь внешний реального самолета, при этом игнорируется его внутреннее устройство, и игрушка таким образом не умеет летать, но наша задача (развлечь ребенка) при этом выполняется.
    Существует несколько парадигм праграмирования. Каждая парадигма это стиль моделирования программы. Затронем например процедурное программирование. В нем существуют для моделирования задачи такие сущности как: структуры данных и процедуры которые эти структуры обрабатывают. Дело в том, что в программе есть всего две еденицы которыми мы управляем: данные и поведение. Структуры данных это собственно данные, процедуры это поведение. Смысл зачем появилось процедурное программирование именно чтобы дать программисту абстрагировать поведение (засунуть код обработки данные в именованную сущность, она еще называется функция или процедура). Что это нам дает? Раньше у нас была простыня кода которая расчитывала например зп сотрудников, если нам нужно было посчитать зп в разных местах нам нужно было копипастить эту простыню. А сначала нужно было разобраться что простыня делает. Это сложно. Теперь у нас появилась именованная сущность (процедура) которпя имеет метку имени calculateSalary. Ну и что? А то, что теперь нам во первых не нужно копипастить код, во вторых (в идеале) не нужно разбираться как он работает. Мы просто знаем что calculateSalary считает зп для сотрудника. Как оно это делает, нам совершенно похер. Снизилась когнитивная нагрузка на мозг при моделировании задачи и повысилась переиспользуемость кода, тем самым сократилось время разработки. Но умные люди на этом не остановились и стали развивать идею дальше. Дальше они подумали, что не плохо было бы обьеденить в одной сущности данные и действия над этими данными, назвали это обьектами, которые могут формироваться на основе классов. Теперь у нас обьеденены данные и процедуры в одной именованной сущности (это инкапсуляция). Подробнее об инкапсуляции можете почитать в другом моем ответе https://qna.habr.com/q/1174988#answer_2194198
    В общем вы не поймете прелесть ООП пока не поработаете по той причине, что нужно набрать массу сложности в проекте, которую генерируете как вы сами так и другие программисты, и не поймете прелесть повторного использования кода которое дает ООП, потому что у вас нет горящих сроков. Тут еще можно в целом много чего написать на тему ООП, но я бы вам посоветовал следующие книги:

    Стив Макконел - Совершенный код
    Гради Буч - Обьектно ориентированный анализ и проектирование
    Сергей Типляков - Паттерны проектирования на платформе .NET (это вместо банды четырех, т.к. там более современно раскрывается тема паттернов, не пугайтесь что она про C# .NET, книга в самом деле очень хорошая)

    Так же список терминов на погуглить
    GRASP - Information Expert
    Information Hiding
    Software Complexity (это то откуда всё начинается, управление сложностью)
    Cohesion & Coupling

    Если вы все эти темы осознаете, то будете понимать в ООП и проектировании больше 95% ваших будующих коллег, я вам гарантирую.
    Ответ написан
  • Инициализация полей объекта данными из $_Post. Не стреляю ли я себе в ногу?

    DollyPapper
    @DollyPapper
    Не уверен, что это то что вам нужно, но посмотрите на эту либу: https://github.com/samdark/hydrator
    Ответ написан
    Комментировать
  • Зачем нужна инкапсуляция в ООП?

    DollyPapper
    @DollyPapper
    Инкапсуляция вообще является (ИМХО) главным принципом из 4. Инкапсуляция + абстракция. Вы не поняли её основную идею. Инкапсуляция это объдинение в одной сущности данных (не обязательно в общем-то) и действий которая эта сущность может предоставить. Инкапсуляция + абстракция представляю собой в общем более общий принцип - сокрытие информации/сложности, и один без другого не сильно то полезен. Не путать с модификаторами доступа (public, private и тд). Этот принцип идет скрозь всю историю развития языков программирования и собственно является главной движущей силой их развития. Вот пример из реальной жизни: есть у вас микроволновка. Она имеет +- 2 нопки: выставить время, выставить мощность. Это интерфейс микроволновки, который доступен конечному пользователю. Всё что вам нужно знать, чтобы приготовить себе похавать - 1)на какой мощности это хавать, нужно готовить 2) сколько это нужно делать по времени. При этом очевидно внутри микроволновки происходит та самая сложность, микросхемы гоняют электрический ток, магнетрон изучает электромагнитные волны, всякая разная физика происходит и вот это вот всё. Итого: вся эти физика и электротехника инкапсулирована в объект микроволновки (инкапсулирована так, что мы не можем добраться до её внутреннего устройства, это важно. Т.е. мы не можем сами соединить проводки, поменять электрическую цель, чтобы себе похавать сделать, разработчик этой электропечки не дал нам даже потенциальную возможность это сделать легально. Можно конечно разобрать устройство и проделать все эти манипуляции, но это уже это на совести того самоделкина, кто это делает). Итого: мы имеем интерфейс из двух кнопок и получаем от обьекта микроволновки услугу - приготовить пожрать. Как там внутри это реализовано, нам не важно. Это и есть инкапсуляция + абстракция = сокрытие информации/сложности.
    Более программистский пример: есть такая структура данных - Стек. Хотя по факту это не структура данных, а абстрактный тип данных. Советую этот термин загуглить, это важная составляющая в понимании ООП.
    Представим, что стек это такой обьект который предоставляет услуги, по типу как мы представляли себе обьект микроволновки. Что нам нужно знать про стек, чтобы им пользоваться? Публичный интерфейс. Т.е. есть класс Stack с публичными методами push(), pop(), viewTopStack() (посмотреть первый элемент стека, без его удаление из самого стека). Всё, можно пользоваться. Как он внутри эти элементы хранит, простой ли это массив, или связный список, на сколько эффективно он там внутри работает - нам не важно. Это важно тому, кто предоставил нам в пользование данный класс. Мы знаем, что вызвав viewTopStack мы посмотрим первый элемент стека, вызвав push - положим что-то в стек, вызвав pop получим первый элемент, удалив его из стека (по аналогии: мы знаем что чтобы притоговить пожрать, нужно выставить в микроволновке время и мощность, на выходе получив наше адово хрючево). Если подытожить - инкапсуляци + абстракция, (еще раз настою на том, что порознь их нельзя рассматривать, это две тесно связанные концепции которые имеют практический смысл только в синергии) это механизм борьбы со сложностью, не только в программировании, вообще везде, в любой человеческой деятельности. В этом их смысл. Если ваши абстракции плохие -> ваш код сложный -> ваш код плохой (говнокодом его еще называют в сообществе программистов).
    Почитать на эту тему можно следующее: Р.Мартин - Чистая архитектура (начать с глав про SOLID прицнипы), С.Макконел - Совершенный код (главу про классы обязательно, остальное желательно (очень желательно)), там в общем-то вам расскажут то что я вам сейчас рассказал, только более подробно, по больше примеров и дадут обоснование сложности, назвав борьбу с ней - Главным техническим императивом. Шлифануть это книгой банды четырех. Сами паттерны не обязательно начинать учить (да и рано вам еще), но вот введение и часть про программирование на основе интерфейса, а не реализации - самое оно, это дополнит картину.

    UPD: тот факт, что мы в классе стек собрали его функционал (функции pop,push,...) обьединенные одной общей темой и есть факт инкапсуляции.
    Ответ написан
    Комментировать
  • ООП: Правильно ли архитектурно так делать?

    DollyPapper
    @DollyPapper
    Оборачивать массивы какой нибудь выборки в объекты для передачи куда нибудь в другой слой или сериализации и передачи по сети это совершенно нормально, ничего в этом такого нет. Скажу даже больше, это оборачивание в "обьект" даже называние специальное имеет - DTO (DataTransferObject), паттерн. Но путать DTO и обьекты не стоит, т.к. по факту это структуры данных. В С#, С и каких нибудь еще языках для этого есть даже ключевое слово struct, но в пыхе мы такого не имеем по этому заворачиваем в обьекты.
    кстати, как называется этот слой приложения, и в чьей зоне ответственности эта задача

    Зависит от вашей архитектуры. Если у вас богатая доменная модельно, то эти методы выборки и создания могут быть прям в модели, если у вас анемичная модель, то существует слой бизнес сервисов в которые выносятся методы работы с вашей бизнес логикой.
    Меня смущает множество классов, которые в себе очень редко содержат какую-то бизнес-логику
    , судя по этому у вас как раз второе. Однако сама выборка из базы это явно не зона ответственности модели, для этого не плохо бы вынести это всё дело в persistanse слой.
    Ответ написан
    Комментировать
  • Где найти книги или курсы по PHP, где даётся проектирование приложений с учётом ООП?

    DollyPapper
    @DollyPapper
    Их не нужно сравнивать. Эти подходы дополняют друг друга. Внутри методов класса ты как ни крути пишешь процедурный код.
    Ответ написан
    Комментировать
  • Всегда использовать Геттеры и Сеттеры хорошо или плохо?

    DollyPapper
    @DollyPapper
    Внутри самого класса можно обращаться к свойствам напрямую. Из вне, лучше это делать через геттеры сеттеры.
    Ответ написан
    Комментировать
  • Плохая практика менять объект ненапрямую?

    DollyPapper
    @DollyPapper
    Нарушаете принцип инкапсуляции как минимум. Сделайте композицию, чтобы в конструктор передавалась начальная позиция персонажа, и метод чтобы менять эту позицию у самого персонажа. Сейчас у вас p
    это не свойство персонажа, а разделенное свойство в области видимости, хотя по логике это именно свойство персонажа.
    Ответ написан
    9 комментариев
  • В чем разница между внедрения зависимостей и наследованием?

    DollyPapper
    @DollyPapper
    Тут как и везде в ООП, вопрос не технический а скорее филосовский. Ваш вопрос наверное лучше задать как - "В чем разница между наследованием и композицией, ведь при композиции мы так же получаем доступ к методам и полям класса". Разница в том, что при наследовании класс становится прямым потомком некоего класса, при композиции данный класс становится частью нашего класса, при этом "родственных связей" между ними нет.
    Ну например было бы логично такое наследование Engine -> Car ? Не думаю. А вот внедрить через зависимость ту же, сделать композицию обьектов, сделать движок частью машины, но не его наследником - это уже логично, это то как мы себе представляем реальный мир.
    Ответ написан
    Комментировать