Pull to refresh

Comments 26

С наследованием перебор. Если развивать ваш класс машины, то начнут появляться вот такие уродцы

RedDiesel4wdManualTransmissionCar, GreenElectric4wdAutomaticTransmissionCar, ...

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

У нас есть методы для зарядки и показа текущего значения, однако мы не даем доступ к самой переменной _batteryLife, поэтому, например, пользователи класса не смогут убавить значение нашей переменной

// Метод заряжает батарею, но не имеет доступа к уровню заряда
public void Charge(int amount)
{
    _batteryLife += amount;
}

Пока пользователь не передаст отрицательное значение в метод Charge

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

public List<string> GetFavorites()
{
    return _favoriteSongs;
}

Вы возвращаете наружу мутабельный тип List<string>, который без проблем можно изменить

Огромное спасибо, что не прошли мимо, поправил.

Вы не сделали лучше на самом деле.

Вы либо вообще не принимайте отрицательные числа, либо как то ошибкой реагируйте на них.

Не нужно просто игнорить их

И почитайте про ReadOnly коллекции например, сейчас не особо лучше стало

У вас, кстати, остался ещё один пример с точно такой же ошибкой с возвратом мутабелтной коллекции

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

Пока пользователь не передаст отрицательное значение в метод Charge

С моей точки зрения, это сущие пустяки по сравнению с главным: так писать вообще не надо. Может быть, кстати, что ошибка возникла именно поэтому — был бы реальный код для реальной задачи, над ним бы думали. Как я заметил, уже много лет среди преподавателей ООП царит какая-то эпидемия: его объясняют на кошечках, собачках и геометрических формах, вместо того, чтобы взять реальный пример — скажем, обёртку над WinAPI. В результате, идея, что классы должны отражать предметную область воспринимается как откровение и её раздувают аж до методологии доменного дизайна (кстати, внутренне противоречивой, ИМХО).


Зачем нужен класс Smartphone? Репрезентовать реальный смартфон с его зарядкой где-нибудь в API? Чтобы получить объект и узнать его характеристики, в т.ч. заряд? Но реальный смартфон не управляет своей зарядкой! И юзер не может дать смартфону команду: «Зарядись!». Юзер может только воткнуть провод, а дальше как пойдёт. Реальный Smartphone не хранит состояние заряда вообще, а лазит за ним в драйвер (скорее всего, открывая порт). И возвращает его в свойстве, а не методе, кстати говоря (я уж молчу, что декомпозиция, при которой уровень батарейки это свойство смартфона, весьма сомнительна). Хранить он может разве что кэш (если чтение дорогое). Почему не написать вот такой настоящий полезный класс для обучения?


Даже если мы пишем не API, а игру-симулятор, где надо заряжать много смартфонов, проблема останется та же самая: смартфон не контролирует свою зарядку. Спроектировано, то есть, неправильно. А потом эти люди приходят в промышленность и начинают писать, как их научили.

а ещё стоит добавить, что в бизнес-приложениях часто распространена анемичная доменная модель

public class HeroesOfMightAndMagic3
{
    public void Play()
    {
        Console.WriteLine("Запускаем классическую версию игры...");
    }
}

public class HeroesOfMightAndMagic3Hd : HeroesOfMightAndMagic3
{
    public void Play()
    {
        Console.WriteLine("Запускаем игру в высоком разрешении (HD)...");
    }
}

public class HeroesOfMightAndMagic3Hota : HeroesOfMightAndMagic3
{
    public void Play()
    {
        Console.WriteLine("Запускаем игру с двумя новыми городами...");
    }
}

Это плохой пример наследования, т.к. вы не переопределили методы в наследниках, а скрыли базовые методы.

На самом деле вся 'статья' крайне низкого качества

Тут нарушается принцип замещения Лисков.

Согласен, поправил.

Спасибо за ещё один пример и за обратную связь. С вашей помощью качество стало чуть лучше.

Буду премного благодарен, если подскажете этому программисту как писать статьи лучше.

За OTUS замечал уже не раз... Вроде бы должны учить доброму, светлому, но порой такое лепят, что есть большие сомнения что там вообще чему-то могут научить. Как из этой статьи человек, решивший познать основные принципы ООП может что-то вообще понять? В подобной статье от того же OTUS https://habr.com/ru/companies/otus/articles/525336/ описание инкапсуляции в корне противоречит описанию из этой статьи. Правда там про полиморфизм тоже начудили. Есть же простые понятные объяснения и определения, данные человеческим языком. Постоянно замечая ошибки, ляпы, закостенелость изложения материала, делаю выводы о квалификации тамошних преподавателей. А ведь они ещё и деньги просят за свои курсы. Никому бы не посоветовал. Ничего не имею против конкретного автора на за OTUS в целом накипело.

10 лет в программировании, все говорят что есть какие то мистические правильные и понятные описания ООП, но все 10 лет выходят статьи где мусолят одно и то же. Может вопрос не так прост, каким кажется?

Тут такое дело. Если начать разбираться, то выяснится, что практика ООП противоречит принципам ООП. Так вообще часто бывает с теорией и практикой. Но тут надо для начала определиться, мы пишем о теории или о практике программирования. В данном случае – ни нашим, ни вашим.

Сокрытие и инкапсуляция это разные вещи. Да, сокрытие по сути обеспечивает инкапсуляцию, но это не означает, что это одно и то же. Инкапсуляция - это объединение данных и методов по их обработке в одну структуру.

Полиморфизм тоже разный бывает. У вас в примере только полиморфизм подтипов, а есть ещё и ad-hoc полиморфизм, и параметримеский полиморфизм. Да и само определение полиморфизм куда глубже. Полиморфизм даже с ООП напрямую не связан, он связан с теорией типов. Полиморфизм - способность программы изменять поведение в зависимости от обрабатываемого типа.

В целом, базовые принципы ООП не такая простая штука, поэтому давать её в самом начале в таком упрощённом виде только вредить, придётся потом переучивать.

Инкапсуляция это и механизм языка, позволяющий скрывать детали внутренней реализации от пользователя и сохранять целостность данных. Собственно определений два и оба они верные.

Верное - это то, которое выражает суть и полноту механизма. Если не выражает, то оно не верное, а вредное.

Примеры уровня: "Заходит как-то раз в бар бесконечное количество математиков..."

"... и начали воображать всякое про ООП."

нафиг они не сдались, тем более начинающему

Как создатель и руководитель курсов по C# я вижу ... Инкапсуляция в программировании сводится к тому, чтобы не давать доступа к важным данным напрямую

О боже, дальше читать не смог, инкапсуляция не про доступ

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

Вот прямо первый пример. Для чего мы инкапсулируем? Наш код обрабатывает наши же данные. Кто "из вне" может получить доступ к этой важной переменной? Почему не сделать её public и не использовать где понадобится? Что за ворота без забора посреди чистого поля? ?

Лично для меня затык с ООП случился по причине резкого изменения темпа обучения - если до ООП усложнение тем идёт пошагово и новые данные органично дополняют предыдущие, помогая и упрощая жизнь как то - switch вместо столбика повторяющихся if-ов, циклы разной степени глубины, функции, упрощающие повторное использование необходимых действий итд, то ООП сходу вываливает кучу деталей, которые нужно понять все и сразу, иначе работать ничего не будет, и при этом необходимость в использовании ООП постигается не через более продвинутый способ решать известные задачи, а с помощью искусственно сконструированных проблем специально "под" ООП. В итоге в голове каша и непонимание а нафига козе баян?

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

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

Sign up to leave a comment.