Pull to refresh

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

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



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


Откуда я узнал о программировании?
— С 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 в главе про ООП была такая фраза: «Если для вас ООП — Организация Освобождения Палестины, обратитесь к другой более фундаментальной книге». Теперь эта фраза ассоциируется у меня с неверным пониманием ООП.
Tags:
Hubs:
+39
Comments 64
Comments Comments 64

Articles