ООП — Организация Освобождения Палестины

    Эта статья является изложением в письменном виде моего личного восприятия программирования и Объектно-ориентированного программирования в частности. Здесь собраны и душевные негодования, и переживания за программистов всего мира. Всё, конечно же, подкреплено исходным кодом.



    Что такое программирование?


    Откуда я узнал о программировании?
    — С 9 по 11 класс в школе учили программировать на Паскале.

    Из чего состояли мои программы?
    — Из процедур и функций, данных и действий над ними.

    Что не понравилось?
    — Когда я попытался написать большую программу, очень долго боролся с ошибками… И чем дальше тем больше их было… Приходилось держать в голове огромный объём информации относительно того как всё работает. Кто кого и откуда вызывает.

    Как я боролся со сложностью?
    — Выделял независимые модули в которых объединял функции по их смысловому предназначению. Отдельно функции для работы с мышкой, отдельно для работы с графикой, отдельно для работы с BMP и т.д.

    Что такое ООП?


    Откуда ты узнал об ООП?
    — На первом курсе института.

    Что именно мне рассказывали про ООП?
    — Трудно вспомнить. Помню классы, наследование, private, public и static.

    Как я пользовался полученными знаниями?
    — Ну создавал классы, как отражение объектов реального мира. Наследовался для расширения функционала некоторого класса.

    Чем мне помогло ООП, стало ли проще писать программы?
    — На первых порах было удобно. Можно было повторно использовать старые классы. Иногда, если требования менялись — я наследовался и изменял в наследнике поведение необходимым образом.

    Что из себя представляют принципы SOLID?
    Что такое интерфейс класса и зачем его явно описывать?
    Что такое отношение общее/частное и часть/целое?

    Если на два предыдущих вопроса вы дали положительный ответ — можете дальше не читать. Далее в статье будет рассказано про интерфейсы, кратко описаны принципы SOLID и приведены 2 основных типа отношений между объектами в объектно-ориентированной программе.

    Что же такое интерфейс?


    Посмотрим на код класса Foo:

    class Foo
    {
        int a;
        static int b;
    
    public:
        Foo() { a = 0; }
        ~Foo() { a = 0; }
        
        int a() { return a; }
        static int b() { return b; }
    
        int sum1() { return a+b; }
        int sum2() { return a()+b(); }
    };
    

    Мы видим несколько видов информации:
    1. Информация о классе
    — поля класса: b
    — методы класса: b()
    2. Информация об экземпляре класса
    — поля экземпляра класса: a
    — методы экземпляра класса: a(), sum1(), sum2()
    — конструктор экземпляра класса: Foo()
    — деструктор экземпляра класса: ~Foo()

    Так вот интерфейсом класса являются следующие данные:
    — методы экземпляра класса: a(), sum1(), sum2()

    Что сделать чтобы описать в явном виде интерфейс на C++?
    — У языка C++ с этим небольшие проблемы (синтаксис оставляет желать лучшего)

    class IFoo
    {
    public:
        virtual ~IFoo() {}
    
        virtual int a() = 0;
        virtual int sum1() = 0;
        virtual int sum2() = 0;
    };
    

    Господи, да что же это такое?
    Виртуальный деструктор: ~Foo().
    — Чисто виртуальные методы: a(), sum1(), sum2().

    И что теперь делать с этим IFoo?
    — Наследоваться от него классом Foo.

    class Foo : public IFoo
    {
        int a;
        static int b;
    
    public:
        Foo() { a = 0; }
        ~Foo() { a = 0; }
        
        int a() { return a; }
        static b() { return b; }
    
        int sum1() { return a+b; }
        int sum2() { return a()+b(); }
    };
    

    Теперь интерфейс класса Foo описан явным образом. Класс Foo можно назвать реализацией (имплементом) интерфейса IFoo. Использовать объекты класса Foo необходимо через интерфейс IFoo следующим образом:

    IFoo * foo = new Foo();
    int a = foo->a();
    int sum1 = foo->sum1();
    int sum2 = foo->sum2();
    

    Что это нам даёт?
    — Ну просто посмотрим на функцию:

    void process(IFoo * foo)
    {
        // ...
    }
    

    В функцию process можно передать любую реализацию интерфейса IFoo. Это может быть и Foo и SuperFoo и GiperPuperFoo.

    В языках C#, Java и прочих имеется ключевое слово interface, которое используется как раз для описания интерфейсов:

    interface IFoo
    {
        public int a();
        public int sum1();
        public int sum2();
    };
    

    В Microsoft Visual C++ имеется ключевое слово __interface, подробнее тут.

    Что же такое SOLID?


    «SOLID это аббревиатура пяти основных принципов дизайна классов в объектно-ориентированном проектировании.» Wikipedia
    S SRP Single responsibility principle Принцип единой разделения ответственности
    O OCP Open/closed principle Принцип открытости/закрытости
    L LSP Liskov Substitution Principle Принцип подстановки Лисков
    I ISP Interface segregation principle Принцип изоляции интерфейса
    D DIP Dependency Inversion Principle Принцип инверсии зависимостей
    Я попытаюсь дать краткую характеристику каждому из них.

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

    Принцип открытости/закрытости требует, чтобы классы, модули, функции были открыты для расширения, но закрыты для изменения. Суть в том, что единожды созданные классы/функции нельзя изменять под конкретные нужды конкретного проекта. Допускается лишь исправлять в них ошибки — не более того. Для изменения поведения некоторого класса/функции необходимо явным образом описать его интерфейс и создать другую реализацию этого интерфейса.

    Принцип подстановки Лисков вообщем говорит о том, что наследование правильно использовать с целью создания программных иерархий типа общее-частное, но не в кое случае не часть-целое. Пример: колеса у машины — это часть-целое, а «колесо легкового автомобиля» относительно обобщённой сущности «колесо» — является отношением общее-частное.

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

    Принцип инверсии зависимостей необходим для обеспечения заменяемости объектов без правок по всему коду и для ослабления зависимостей в коде. Когда у вас есть класс A, имеющий указатель на класс B — классы считаются сильно связанными. Для замены класса B на любой другой, придётся исправлять код класса A — что не есть хорошо. Предлагается вывести интерфейс класса B, назовем его IB. Изменить тип указателя в классе A на IB. Таким образом зависимость A-->B заменилась на A-->IB<--B. Теперь можно вместо B использовать любую другую реализацию интерфейса IB.

    Что есть объектно-ориентированное проектирование?


    Объектно-ориентированная программа состоит из классов. В процессе работы программы создаются экземпляры классов, взаимодействуют с другими экземплярами и завершают своё существование. Взаимодействуя с себе-подобными классы образуют два типа иерархий:
    — Иерархия отношения часть/целое
    — Иерархия отношений общее/частное

    Как выглядит иерархия отношений общее/частное?

    — Иерархия видов наземного транспорта:


    — Иерархия видов колёс:


    Как выглядит иерархия отношений часть/целое?

    — Иерархия легкового автомобиля:


    При проектировании системы необходимо определить иерархии обоих видов.

    Зачем это нужно если и так всё работает?


    ООП было создано для «понижения сложности программы»! При правильном использовании Ваши программы могут стать крайне простыми по своей внутренней структуре. Вы, как программист, просто обязаны быть ленивы)) Так вот вам способ понизить сложность ваших программ, уменьшить связность и т.д.

    Рекомендуемая литература


    1. Чистый код. Роберт Мартин (OZON.ru)
    2. Рефакторинг. Улучшение существующего кода. Мартин Фаулер (OZON.ru)
    3. Объектно-ориентированный анализ и проектирование с примерами приложений. Гради Буч (OZON.ru)
    4. Приемы объектно-ориентированного проектирования. Паттерны проектирования. Э. Гамма, Р. Хелм, Р. Джонсон, Дж. Влиссидес (OZON.ru)

    P.S. В дной из книжек по программированию под J2ME в главе про ООП была такая фраза: «Если для вас ООП — Организация Освобождения Палестины, обратитесь к другой более фундаментальной книге». Теперь эта фраза ассоциируется у меня с неверным пониманием ООП.
    Поделиться публикацией

    Комментарии 64

      +1
      не имплементом а реализацией
      и в С++ далеко не обязательно делать полностью виртуальный класс для реализации поведения интерфейса — множественное наследование зачастую решит все проблемы, при этом контроль типов не пострадает
        +4
        Согласен, заменю американизм имплемент на реализацию. Не согласен, от этого код не только не станет чище, но и появятся новые зависимости, которые увеличат сложность вашей программы((
        –15
        На хабре действительно есть люди, каким-либо образом связанные с программированием и не знающие чего-либо из описанного в статье?
          +17
          Хабр читают не только люди с хабра. Это отличный источник статей для школьников/студентов. И да, я уверен не все люди на хабре знают то что описано в статье… Можно голосование замутить…
          +2
          Я не знал, что такое SOLID. Да и зря узнал, мини-вытяжка из принципов проектирования, для тех, кто не осилил принципы проектирования.
            +2
            Какие «принципы проектирования» вы имеете ввиду? Книга? На вики?
            Эталона то нет. Сошлитесь на какой-нибудь источник информации…
              +1
              Я говорил не о конкретном источнике, а в целом, про объектно-ориентированное проектирование, паттерны, хорошие решения в различных архитектурах.

              Ну вот, к примеру, книга 'Приемы объектно-ориентированного проектирования / Паттерны проектирования' молчит про SOLID. Быть может, конечно, я не внимательно читал, и все же…
                +2
                1994г — Приемы объектно-ориентированного проектирования. Паттерны проектирования
                2000г — SOLID (Роберт Мартин) — link
                  –1
                  Что-то я потерял нить разговора.
                  У вас есть вопросы, замечания к моему комментарию?

                  P. S. Я имел в виду книгу E. Гамма, Р. Хелм, Р. Джонсон, Д. Влиссилес (питер 2006). Find фоксит ридера не обнаружил там такого слова, по вашей ссылке тоже.
                    +1
                    Это переиздание 2006 года. Книга была написана в 1994 году. link
                    А статья Роберта Мартина с аббревиатурой SOLID появилась в 2000 году.
                      –1
                      Прошу прощения, не сразу въехал в 1994, 2000.

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

                      Аббревиатура солид уже стала популярной? Как часто вы ее видете в статьях, книгах?
                        –1
                        Потому и написал целую статью)) Если не давать коротких, запоминающихся имён принципам — очень легко забыть часть и них… Аббревиатура широко известна в узких кругах))
                          +1
                          Я вот дважды за последние пару дней столкнулся с этой аббревиатурой, до этого даже не слышал.

                          P.S. И, имхо, переводить «Single responsibility principle» как «Принцип единой ответственности» не вполне корректно, как-то смысл искажается до обратного, м.б. лучше «Принцип разделения ответственности»? «Трудности перевода»)
                            +1
                            Имелось ввиду один объект — одна ответственность. Возможно стоило применить слово единичный
                              +1
                              Действительно, замените, пожалуйста. «Единой» — это означает «каждый ответственен за всё». «Единичной» — нет такого оборота в русском языке. MaratGilyazov предложил, думаю, удачную формулировку. (Хотя такого перевода не встречается, чаще всего используют «принцип единственности ответственности», реже — «единственной», ещё реже — «персональной» (The Single Responsibility Principle) — подчёркивая, как в оригинале, что 1 ответственность — 1 объект.)
                                +2
                                Подправил
                    0
                    Вообще в первой главе GoF (книга Паттерны проектирования) имеются описание некоторых принципов. Но они там не все, конечно же. Иначе бы Роберту Мартину было бы нечего делать в 2000 году :)
                      +1
                      SOLID — это как-раз таки попытка сформулировать базис для правильного дизайна. Это не столько паттерны, сколько принципы, на которых строится гибкая архитектура системы. Кроме того, на паттернах от GoF мир клином не сошелся) Помимо них, есть и другие, не менее известные. Те же паттерны enterprise приложений от Фаулера — ActiveRecord, Repository, QueryObject и т.п.
                  +1
                  да есть. 20 лет увлечения программированием, 15 лет получаю деньги за свою работу, десятки успешных проектов. И с удовольствием прочитал статью.
                  +3
                  Очень здорово расписал: подробно и достаточно понятно, чтобы можно было сообразить «с нуля». Разве что, я бы привел некоторые примеры к SOLID, потому что, например, LSP, по-моему, был бы понятнее, если на примере показать, что там, где ожидается базовый класс, можно подставить производный.
                    +4
                    По моему мнению, получилась очень холиварная статья, с очень большим количеством пробелов в самых важных местах.

                    Тот материал, который вы здесь пытаетесь подать для начинающих, для этого слишком сухой. И ссылки на сторонние ресурсы(включая википедию) мало спасают положение. скорее еще больше запутывают.
                    Гораздо проще понять принципы ООП, на конкретных примерах проектирования, как это сделано у GOF. Но GOF все таки больше ориентирован уже на людей с опытом.
                      +2
                      Я не пытался разъяснить все принципы подробно. Я пытался направить людей в правильное русло. Везде, где необходимо приёл ссылки для глубокого изучения. Возможно в следующих статьях я проедусь отдельно по SOLID, по наследованию и т.д.))
                      +4
                      На мой взгляд ООП, само по себе, без применения паттернов, вообще мало оправдано, разве что на выходе чуть менее густая каша из кода.
                        +2
                        Если ООП использовано правильно, то как минимум в проекте должна была получиться слабая связанность компонентов между собой. Это уже неплохо, даже без паттернов. А если еще и паттерны используются, то ваще комильфо))
                        +5
                        Так а что с Палестиной?
                          +1
                          Чуть ниже ответил…
                          +4
                          к чему такой заголовок?
                            +7
                            В дной из книжек по программированию под J2ME в главе про ООП была такая фраза: «Если для вас ООП — Организация Освобождения Палестины, обратитесь к другой более фундаментальной дисциплине». Теперь эта фраза ассоциируется у меня с неверным пониманием ООП.
                              +1
                              Весто «дисциплина» подставьте слово «книга». Отвлекся немного.
                                +1
                                Теперь понятно. Просто если делать такие заголовки, то объяснять обязательно нужно, что к чему
                                  +1
                                  Дописал к статье)
                                0
                                понял :-)
                              +8
                              Вот в примерах все так всегда радостно, легко и просто, только вот в реальности все далеко не однозначно. Не всегда можно точно определить иерархию (хорошо, когда это физические объекты физического мира, а если это какие-то процессы), да и не всегда стоит разбивать все идеально (в смысле может оказаться, что кода стало много больше, но не сильно проще). Вообще, разработчик должен думать и понимать, для чего все это придумано. Все эти подходы, принципы, паттерны, фреймворки, <подставьте любое другое модное слово сюда> — это инструменты для того, чтобы сделать жизнь проще но даже хорошие инструменты не во всех случаях применимы. Только вот об этом как-то всегда забывают писать. Но это так, мое личное мнение.
                                +3
                                bestPractices и паттерны применимы всегда. И про их неприменимость пишут те, кто их применял не совсем правильно или нет тот шаблон выбирал. Попробуйте решить проблемы в старом коде с помощью рефаторинга + паттернов. Возможно многое прояснится.
                                Шаблоны — это суха выжимка, опыт программистов по уже решённым задачам, имеющим общие основы. И вы в своих задачах лишь уточняете конкретную реализацию шаблона. Словно вам дали трафарет, вы буквы обвели, а выбор цвета и составление слов — это уже ваше дело.
                                  –1
                                  Почитайте уж что ли про «серебряные пули», паттерны и прочее — это как раз они и есть. До них были и после них будут.
                                    +6
                                    Так в том то и дело, что нет универсальных подходов, которые работают всегда и всюду. Где-то работает то, где-то это, а где-то лучше и без них в принципе. Плюс многие подходы — это компромис между чем-то и чем-то. Выбираем Х — отдаем предпочтение объему кода, который следует написать простоте поддержки. Выбираем Y — отдаем предпочтение простоте понимая кода, но теряем производительность. Выбираем Z — получаем решение, которое легко использовать, но сложно расширить. Причем для каждого проекта эти компромисы отличаются и применение одного и того же подхода будет давать разные результаты.
                                    Я не говорю, что шаблоны — это плохо, но надо всегда понимать, что мы получаем при их использовании и чем мы за это платим.

                                    Приведу пример (пример достаточно абстрактный, но право на жизнь имеет):
                                    Есть всем известный и понятный singleton и применили мы его например к классу, который отвечает за вывод отрендеренного изображения на монитор. Допустим, что у нас есть проект, где что-то программно рендерится и показывается юзверю в каком-то окне. Т.е. этот класс получает результат рендеринга или какой-то текст для оверлея и показывает его в основном окне программы. Мы знаем, что юзверь всегда использует полноэкранный режим и окно всегда одно, поэтому и выбрали синглтон. На какой компромис мы при этом пошли? Мы сделали нашу жизнь немного проще: теперь из любого места программы мы можем отправить в главное окно какие-то данные вроде финального кадра, или счетчика производительности или какую-нибудь иконку и оно там появится. Но, с другой стороны, мы сильно ограничили возможность расширения нашего приложения. Если через год мы вдруг захотим показывать два главных окна (для многопользовательской игры или с разными вариантами рендеринга), нам может понадобиться менять довольно много кода. И это не плохо, это просто та цена, которую мы заплатили за простоту использования синглтона в первый год разработки.

                                    Причем такой пример можно привести и для практически любого другого метода, все эти методы позволяют находить какой-то компромис между какими-то свойствами. Если одно из этих свойств не важно для проекта, значит мы получили улучшение почти бесплатно, но надо понимать, что мы все-таки чем-то пожертвовали.
                                      +1
                                      Отличный комментарий. Побольше бы таких)
                                        0
                                        Безусловно
                                          +1
                                          Да, я вас понимаю. И я писал о том, что каждому шаблону свое место и время.
                                          Но боюсь что некоторые понимают ваши слова иначе:
                                          «Я не говорю, что шаблоны — это плохо, но надо всегда понимать, что мы получаем при их использовании и чем мы за это платим.»
                                          == да ну их нафиг, эти шаблоны. Знаю я про синглтон и фабрику и с меня хватит. Жили без них и дальше проживём, «лишь, были б жёлуди, ведь я от них жирею...»

                                      +4
                                      Одна из главных проблем нашего обучения — это то, что на практике нам разрешают использовать переменные с именем tmp,tmp1,tmp2 (это еще хорошо будет, что не только один tmp), а примеры нам показывают с именами методов Sum1, Sum2.
                                      На уроках русского языка нам не разрешают писать слова с ошибками, когда мы учим правила пунктуации. А на уроках физики нам прививают использовать правильные имена переменных для формул.
                                        0
                                        Таки правда. А еще есть радостные переменные a, b,…
                                        А потом пишутся длиннющие комментарии, чтобы пояснить, что же такое делается там, где достаточно было бы просто нормальные названия использовать…
                                        +3
                                        Статья неплохая, но уж больно маленькая. Тут можно книгу написать, а не статью. Кстати, аббревиатуру я эту не знаю при том, что каждый в отдельности принцип мне известен и я лично их повторяю всем вновь прибывшим на мою работу. Они больше касаются дизайна с использовнием наследования, но можно привести и другие концепции проектирования ООП-программ, которые тоже следует учитывать. Вообще не хватает строгой теории, которая, например, описывает функциональное программирование.
                                          0
                                          Вот я тоже впервые услышал данную аббревиатуру недавно на собеседовании в одну компанию. Думал, что что-то упустил серьезное в обучении. Пришел домой — посмотрел и расстроился, что знаю каждый принцип, но просто не знал, что это так называется. Мне кажется, что не есть хорошо, когда на собеседовании спрашивают аббревиатуры — ведь в мире множество определений под одну и ту же структуру. Конечно, надо знать бОльшую часть, но ведь не это самое важное, как мне кажется
                                            0
                                            Да, особенно по телефону. Там часто сидят девочки с бумажкой вопрос-ответ.
                                          +1
                                          Только мне кажется что принципы Single responsibility и Interface segregation — почти синонимы? Я пытаюсь представить себе ситуацию, когда все классы такие из себя модные «single responsible», но вот зато интерфейсы у них такие страшные — все в одном. У меня как-то плохо выходит…
                                            +1
                                            Видно вставили чтоб аббревиатуру поправить, ато вначале у них выходило SOLD ;)
                                              +2
                                              О нет! Ведь из этого бы следовало что уважаемый Robert C. Martin выбирал свои «five basic principles» исходя из красочности получаемой аббревиатуры, а вовсе не из «реальной базисности» этих принципов. Мы же не можем допустить такой кощунственной мысли, правда?
                                              +2
                                              Немного разные вещи. ISP заключается в предоставлении конкретным клиентам минимального интерфейса. Т.е. предположим, что есть класс Rectangle, который умеет возвращать свой периметр и свою площадь. Пусть эти два метода находятся в интерфейсе IShape. Принцип SRP здесь соблюдается, так как зона ответственности этого класса — некие математические операции с данными этого класса. С точки зрения ISP, если у нас есть класс B, который выполняет операции с площадью некоторого объекта, при этом ему не требуется периметр этого объекта, то неплохо было бы разделить интерфейс IShape на какой-нибудь IShapePerimeterProvider и IShapeSquareProvider.

                                              Пример, конечно, надуманный и названия интерфейсов не самые удачные) Суть в том, что SRP — это не одна операция на класс, это скорее операции одного контекста. Т.е. когда Rectangle не только умеет считать свою площадь, но и ещё умеет себя отрисовывать, и при этом используется в двух подсистемах — в одной только для получения площади, а в другой — для отрисовки — это уже нарушение SRP.
                                                0
                                                «Area», конечно, не «Square». Кстати, у самого Роберта Мартина в его «Design Principles and
                                                Design Patterns» 2000 года не было SRP. С другой стороны, DIP он описывал ещё в 96ом)
                                                  0
                                                  Хм… на самом деле, после вашего примера, разница между ISP и SRP стала более различима — спасибо!
                                                +1
                                                >Принцип подстановки Лисков вообщем говорит о том, что наследование правильно использовать…
                                                Принцип подстановки Лисков говорит, что там, где используется наследуемый класс, может быть использован и наследник. И ничего не говорит о правильном/неправильном использованиие наследования.

                                                Насчет DIP — это нужно использовать только там, где нужно. Тоесть там, где отсутствие инверсии не дает использовать компонент высшего уровня, так как он жестко завязан на компонент низшего уровня.
                                                Новичок, прочитав статью, может подумать, что это нужно делать с каждым классом и будет плодить никому не нужные интерфейсы.
                                                  +1
                                                  LSP, кстати в оригинале звучал как «functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it», а не про as-is, как это описано у автора поста.
                                                    +2
                                                    в оригинале принцип звучал так: «What is wanted here is something like the following substitution property: If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T

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

                                                    кстати, принцип имеет импликативную форму (A => B), а это значит, что обратное утверждение в нём не сформулировано. следовательно, на основании данного принципа нельзя утверждать обратное: дескать, «правильное» наследование — когда S is a subtype of T — обеспечит неизменность поведения вашей программы при использовании объектов первого типа, вместо объектов второго типа. чем, кстати, в некоторых кейсах ООП активно пользуются — передавая программе разные объекты для того, чтобы изменить её поведение. образно говоря, хотя тип «колёса легкового автомобиля» являются конкретизацией типа «колёса», легковушка может вести себя на дороге по-разному, в зависимости от конкретной «резины».
                                                      +1
                                                      Да, согласен, в качестве оригинала я имел в виду трактовку Роберта Мартина.
                                                    0
                                                    По смыслу своему, интерфейсы — это сущности, описывающие свойства чего-то. А классы — сущности, описывающие совокупности объектов — в частности, удовлетворяющих каким-то свойствам.

                                                    Поэтому вполне логично считать, что «родной» частью речи, которую надо использовать для именования классов, является существительное (Square, Circle, Human, Connection). А частью речи, которую надо использовать для именования интерфейсов, является причастие (Serializable, Sortable, Parseable), ну, или с натяжкой — прилагательное.

                                                    Я это к тому, что нарушение подобных «мнемоник», очень вероятно, может быть вызвано непониманием архитектуры или неправильным проектированием. Ну, например, создавать интерфейс ICanvas и класс CanvasImpl.
                                                      0
                                                      Собственно об этом и говорится в тексте по моей ссылке.
                                                        0
                                                        В идеале это конечно может и так, но как мне кажется, тут есть проблема. В дело вмешиваются DI и Mocks и оказывается, что без интерфейсов объектов именно в таком виде, как вы написали обойтись достаточно проблематично. Класс все-таки представляет больше, чем совокупность функциональности, которую можно представить такого рода интерфейсами-наречиями, там еще есть смысловая часть.
                                                        Вот это ядро тоже необходимо обернуть в интерфейс, для поддержки тестируемости, именно тогда и появляются такие интерфейсы типа ICanvas.
                                                          0
                                                          Вы совсем не поняли, о чем говорится в блогозаписи по ссылке. Речь идет о том, что если есть какой-то интерфейс, который содержит, например, методы по доставанию объекта по id и его реализации, одна из которых, например, ходит в базу, а вторая — получает доступ их через web-services, то нужно делать такую иерархию: ObjectLoadingService — интерфейс, JDBCObjectLoadingService — реализация которая ходит в базу, WebServicesObjectLoadingService — реализация через вебсервисы соответственно. А не IObjectLoadingService и ObjectLoadingServiceImpl и ObjectLoadingServiceWebImpl.

                                                          DI и моки тут вообще ни при чем.
                                                    –1
                                                    Еще один copy-paste давно известных истин.
                                                      +1
                                                      Плохо. Вы приводите примеры кода для того, чтобы показать разницу между классом и интерфейсом — для самой простой части. И не приводите примеры для куда более сложных вещей. Почему это я должен делать класс с единственной ответственностью? Приведите пример, покажите, как трудно поддерживать код, который нарушает этот принцип. Желательно сделать тоже самое и для остальных принципов. Гляньте в Code Complete Макконнелла. Этот человек ни единого правила без примера не оставляет, даже на предмет именованных констант.
                                                        0
                                                        В «чистом коде» SOLID рассматривается? Какой объем материала по сравнению с «быстрой разработкой»?
                                                          0
                                                          Стоит добавить, что в таком виде этот свод правил применим к статическим языкам. При программировании на том же JS принцип Open/Close часто нарушается ко всеобщей пользе — и на питоне, вроде, тоже…

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

                                                          Самое читаемое