ООП с примерами (часть 2)

    Волею судьбы мне приходится читать спецкурс по паттернам проектирования в вузе. Спецкурс обязательный, поэтому, студенты попадают ко мне самые разные. Конечно, есть среди них и практикующие программисты. Но, к сожалению, большинство испытывают затруднения даже с пониманием основных терминов ООП.

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

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


    Инкапсуляция


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

    Теперь вернёмся в сегодняшний день к современным чудесам автопрома с коробкой-автоматом. На самом деле, по сути, ничего не изменилось. Бензонасос всё так же поставляет бензин в двигатель, дифференциалы обеспечивают поворот колёс на различающиеся углы, коленвал превращает поступательное движение поршня во вращательное движение колёс. Прогресс в другом. Сейчас все эти действия скрыты от пользователя и позволяют ему крутить руль и нажимать на педаль газа, не задумываясь, что в это время происходит с инжектором, дроссельной заслонкой и распредвалом. Именно сокрытие внутренних процессов, происходящих в автомобиле, позволяет эффективно его использовать даже тем, кто не является профессионалом-автомехаником с двадцатилетним стажем. Это сокрытие в ООП носит название инкапсуляции.

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

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

    Абстракция


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

    Абстрагирование – это способ выделить набор значимых характеристик объекта, исключая из рассмотрения незначимые. Соответственно, абстракция – это набор всех таких характеристик.

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

    Полиморфизм


    Любое обучение вождению не имело бы смысла, если бы человек, научившийся водить, скажем, ВАЗ 2106 не мог потом водить ВАЗ 2110 или BMW X3. С другой стороны, трудно представить человека, который смог бы нормально управлять автомобилем, в котором педаль газа находится левее педали тормоза, а вместо руля – джойстик.

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

    Полиморфизм – это свойство системы использовать объекты с одинаковым интерфейсом без информации о типе и внутренней структуре объекта.

    Например, если вы читаете данные из файла, то, очевидно, в классе, реализующем файловый поток, будет присутствовать метод похожий на следующий: byte[] readBytes( int n );
    Предположим теперь, что вам необходимо считывать те же данные из сокета. В классе, реализующем сокет, также будет присутствовать метод readBytes. Достаточно заменить в вашей системе объект одного класса на объект другого класса, и результат будет достигнут.

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

    Наследование


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

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

    Очевидно, что все три модификации будут иметь большинство свойств прежней модели (старый добрый двигатель 1970 года, непробиваемая ходовая часть, зарекомендовавшая себя отличным образом на отечественных дорогах, коробку передач и т.д.). При этом каждая из моделей будет реализовать некоторую новую функциональность или конструктивную особенность. В данном случае, мы имеем дело с наследованием.
    Наследование – это свойство системы, позволяющее описать новый класс на основе уже существующего с частично или полностью заимствующейся функциональностью. Класс, от которого производится наследование, называется базовым или родительским. Новый класс – потомком, наследником или производным классом.

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

    Действительно, в нашем примере мы могли бы произвести с новыми автомобилями все те же действия, что и со старым: увеличить или уменьшить скорость, повернуть, включить сигнал поворота. Однако, дополнительно у нас бы появилась возможность, например, включить противотуманные фонари.

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

    Похожие публикации

    Комментарии 37
      +1
      Спасибо. Уточнил для себя некоторые моменты.
        +3
        Абстрагирование менее удачный пример нежели последние два. А вообще очень толково, я б на ваших лекциях не болтал.
          0
          Спасибо. Про абстрагирование признаюсь честно — за час до начала лекции спохватился, что этого раздела нет и спешно дописывал. Поэтому получилось немного сумбурно…
          –4
          О да, полиморфизм и инкапсуляция. Ну хоть убей я не расскажу вам быстро, что есть то и что есть это :) Ну знаю, подумаю и отвечу. Но сходу — низачто. ДУмаю ваша статья продлит мою память подольше :)
            0
            Признание своих недостатков уже считается постыдным? Забавно.
              –2
              всем похуй
            +1
            Вот у ВАЗа плохо с инкапсуляцией и наследованием ИМХО :)
            • НЛО прилетело и опубликовало эту надпись здесь
                +2
                у ВАЗа плохо с РЕАЛИЗАЦИЕЙ интерфейса автомобиля.
              • НЛО прилетело и опубликовало эту надпись здесь
                  0
                  хочу на Ваши лекции.
                  спасибо :)
                    +1
                    >Абстрагирование – это способ выделить набор значимых характеристик объекта,
                    >исключая из рассмотрения незначимые. Соответственно, абстракция – это набор всех
                    >таких характеристик.

                    Вот это определение кажется мне особенно неправильным.

                    Хорошо бы добавить объяснение связи между наследованием и полиморфизмом.
                      0
                      Вы имеете в виду, что на самом деле абстрагирование — это способ сконцентрироваться на интерфейсе, не обращая внимания на реализацию? Действительно, думаю что имеет смысл изменить.

                        +1
                        Я имел ввиду, что абстрагирование — способ описания общих характеристик, а не значимых или не значимых. Как раз значимая для класса характеристика абстрактной может и не быть.
                      +1
                      «Инкапсуляция неразрывно связана с понятием интерфейса класса. По сути, всё то, что не входит в интерфейс, инкапсулируется в классе.»
                      Инкапсуляция не имеет никакого отношения к интерфейсу, а только к классу.
                        0
                        Может быть, я немного не так выразился. У класса есть быть определённый интерфейс, т.е. набор открытых методов, а вся остальная функциональность инкапсулируется.

                        Я не имею в виду интерфейс в понимании языка программирования (например, interface у Java).
                          +1
                          Интерфейс — языко-независимое понятие. Давая определение интерфейса через класс и инкапсуляции через интерфейс, вы ставите телегу впереди лошади.
                          Пример. Оглобли — это видимая часть лошади(упряжи) или оглобли — это НЕ внутренние (скрытые) органы лошади. Оба утверждения верны, но в реальности оглобли — это две палки, определенной длины.

                          Кстати, а чем вас классический пример (по-моему он был у Гради Буча) про геометрические фигуры не устроил?
                          0
                          Жаль, что у нас в Вузе лекции по программированию читались не так. Впрочем, для нас программирование не было основным предметом.
                            +1
                            То что у вас написано в разделе Полиморфизм — это определение интерфейса.
                            Полиморфизм — это множественность (поли-) изменений (-морфизм). Типичный пример — реализация класса может быть изменена в процессе наследования. Например, установка гидроусилителя руля или турбины в уже работающий автомобиль, который вы унаследовали от дедушки. Тем самым, вы ИЗМЕНЯЕТЕ автомобиль не затрагивая внешний интерфейс.
                              0
                              Позволю себе с вами не согласиться.

                              Всё таки, это греческий термин, а не английский. «Морф» — это форма по-гречески.

                              Т.е. полиморфизм — это «множество форм», используемых в одном контексте. Мы можем взять одну форму, а можем — другую, но содержание не изменится.

                              То, что вы описали — это просто одно из свойств наследования. Действительно, добавляя ГУР и турбину в один автомобиль, мы не требуем, чтобы у нас было несколько однородных (читай — с одним интерфейсом) объектов. Достаточно, чтобы был предок и потомок с внесёнными изменениями.

                              Ключевым моментом в полиморфизме является именно способность использовать объект вне зависимости от его реализации. Вы же согласитесь, что на практике полиморфизм можно применять, не используя наследование, а используя лишь контракт класса (ну, или интерфейс)? Для примера, можно взять implements в Java.
                                +1
                                Да, вы правы насчет термина. И мой пример — частный случай применения полиморфизма.
                            • НЛО прилетело и опубликовало эту надпись здесь
                                0
                                Да, действительно пример полиморфизма. Но, к сожалению, мы опять уходим на иллюстрацию кодом. Это практика. Она немного за пределами данной лекции.

                                Но, скажу по секрету, я именно этот пример приводил, когда говорил студентам про практическую реализацию. Обход списка объектов разных классов и печать некоторой информации по каждому.
                                0
                                кстати эта статья понравилась больше первой :)
                                  +7
                                  Мда… Прямо ребятам о зверятах. И это рассказывают в ВУЗе? На профильном предмете?
                                  Я понимаю, если бы это был факультатив для старшеклассников, но для вуза это вообще не серьезно.
                                  И полиморфизм, и инкапсуляция отлично живут и без ООП и классов, и давать эти определения на основе ООП-шных классов — это все равно, что, ну не знаю, производные без пределов рассказывать, это как заклинание зазубрить. Это для вуза? При этом сухие формальные определения, в данном случае, гораздо понятнее, чем наглядные метафоры вокруг автомобиля.

                                  Полиморфная переменная, это переменная, которая может принимать значения разных типов. Все, дальше весь полиморфизм строится на этом определении:
                                  Полиморфная функция, это функция у которой хотя бы один аргумент является полиморфной переменной.
                                  Выделяют два вида полиморфных функций:
                                  — ad hoc, функция ведет себя по разному для разных типов аргументов, например, функция Draw — рисует по разному фигуры разных типов.
                                  — параметрический, функция ведет себя одинаково для аргументов разных типов, например, функция Add — одинаково кладет в контейнер элементы разных типов.
                                  И это все не имеет никакого отношения к классам и ООП.

                                  Если язык не оборудован поддержкой полиморфизма, то такой полиморфизм называется искуственным, пример — Си-шная функция printf — информация о типах аргументов пропихивается отдельным параметром. Если же язык обородован такой поддержкой, то полиморфизм считается естественным, пример — неявный аргумент this в том же C++.
                                  Вот здесь уже можно начинать рассказывать про ООП, и есть повод объяснить, что наследование в статически типизированных ООП языках появилось именно для поддержки полиморфизма и не забыть упомянуть про наследование контрактов и реализаций.
                                  С инкапсуляцией та же история…
                                  А так можно вырастить только специалистов по «Си с классами», а не людей понимающих что такое ООП и чего от него ждать.
                                    +1
                                    а вы сами то преподаете? если нет, то наверное у вас нет понимания, что сейчас творится в ВУЗах. я сам как студент пятого курса ИТ прекрасно понимаю, для чего тут «ребятам о зверятах».
                                    Вот честное слово, я бы и половине своего потока не дал бы и средне технического образования. Там полно людей которые дроби то не умеет складывать, а вы тут со своими ad hoc; )
                                    и большинство из них получат свои дипломы. Главная сила, которая заставляет их тупо ходить в инстик — «без бумажки ты букажка». Причем этот аргумент звучит и на зачете, я не знаниями — я за зачетом…
                                      0
                                      Да, преподаю. В ВУЗе.
                                      То, что студенты учиться не хотят — это не проблема. Проблема в том, что даже если и хотят, то иллюстрациями на машинках знания по ООП до них не донесешь. По моему мнению, преподавание в ВУЗе должно вестись на совершенно другом уровне. Может быть мне повезло и в свое время я еще застал то, как это должно быть, на излете правда, но то как дают это сейчас вызывает только уныние.
                                        0
                                        Большая проблема в преподавании компьютерных наук — то, что обычно их читают теоретики. Это безусловно очень важно, и серьёзно, т.к. в первую очередь, это — наука. Но я чистый практик. И моя задача научить ребят не абстрактной теории, которой, я очень надеюсь, им хватило на предыдущих курсах, а тому, как сейчас используется эта наука. Т.е. чистой практике.

                                        В своё время, после выпуска я сразу попал в фирму, которая занимается серьёзной разработкой ПО. И там я понял, что вся эта теория становится практически бессмысленной, к сожалению. Нам забивали голову жордановой формой матрицы и уравнением колебания струны, но, «как писать программы», никто так и не научил. Были несколько хороших молодых преподавателей, которые давали именно практические, действительно полезные знания, но их оказалось достаточно только для того, чтобы пройти собеседование при устройстве на работу.

                                        Я перед собой ставил задачу — показать, как использовать ООП на практике. Основная цель курса — паттерны проектирования. Если я буду углубляться в теорию, то мне понадобится 5-7 лекций только на то, чтобы в очередной раз «запудрить мозг» студентам теорией, в результате чего, на собственно, сам предмет осталось бы 2-3 лекции от силы.

                                        Отсюда — «ребятам о зверятах», отсюда игнорирование, безусловно важных и интересных теоретических моментов. И, да, Вы правы, моя цель действительно вырастить специалистов «по Си с классами», т.к., иначе, заканчивая университет, студенты даже «Си с классами» знать не будут.
                                          0
                                          Вы наверное ВУЗ с техникумом или ПТУ перепутали, вот там действительно нужна суровая практика и ничего больше.
                                          Помимо того, что я иногда преподаю, на основной работе я руковожу группой разработки в «фирме, которая занимается серьезной разработкой ПО», и в связи с этим могу рассмотреть ситуацию со всех сторон.
                                          Так вот, мне, как практику, от стажера знания «си с классами» на уровне машинок, не только не нужны, но и вредны, потому что в этом случае его все равно приходится переучивать. Понимать ООП на таком уровне, я и сам в состоянии его обучить за пару недель. Собственно, ровно по этому у нас в компании, на начальные позиции, предпочитают брать вообще не имеющих никакой подготовки, чем обремененных знаниями о такой «практике».

                                          В то же время сейчас бывает так, что мне, как практикующему разработчику с довольно серьезным опытом и не плохой квалификацией, тем не менее, не хватает теоретических знаний, которые мне могли бы дать в ВУЗе — приходится наверстывать. С другой стороны, не смотря на то, что моя специальность вообще теоретическая физика, и, казалось бы, теоретические знания о фуллереновых пленках и уравнении описывающим изменение состояния задаваемого волновой функцией в гамильтоновых квантовых системах, на практике мне не нужны, наверстывание это больших проблем не составляет, так как в ВУЗе мне преподавали не «практику», а учили обращаться с теорией. Как говорил нам один из преподавателей — «мы учим вас видеть за формулой процесс». Ваш же подход заставляет просто заучивать формулы, причем зачастую неверные.

                                          Кроме того, я не понимаю этого противопоставления «теории» и «практики». CS одна из тех редких областей, где от теории до практики вообще полшага, все на расстоянии нескольких строк кода, как не понимая этого вообще можно преподавать? Доходчиво объяснить не только основные постулаты ООП, но и откуда у них растут ноги, займет не на много больше времени, чем рассказы о машинках. Собственно, непосредственно против машинок я ничего не имею, плохо то, что они являются основой на которой все строится, а не метафорой призванной лишь проиллюстрировать один из аспектов.
                                            0
                                            Если не секрет, какой курс читаете? Мне, действительно интересно.

                                            >Собственно, ровно по этому у нас в компании, на начальные позиции, предпочитают брать вообще не имеющих никакой подготовки, чем обремененных знаниями о такой «практике».
                                            О какой практике? Мне кажется, Вы делаете вывод о содержании курса на основе вступительной лекции. Если в вашей компании удобнее брать людей, не знающих, что такое абстрактная фабрика, стратегия или декоратор, то либо я неправильно понимаю направление вашей деятельности, либо у вас достаточно времени и бюджета, чтобы этому обучать по ходу работы, на «живых» продуктах.

                                            > плохо то, что они являются основой на которой все строится, а не метафорой призванной лишь проиллюстрировать один из аспектов
                                            Я не очень понятно описал проблему. Теоретически (согласно учебной программе), к пятому курсу ООП они знают и в нём разбираются. У них целый год на третьем курсе теоретические основы ООП ведутся. Моя задача — познакомить их с применением этого ООП на практике. В наиболее распространённых случаях. Т.е. показать, что такое паттерны проектирования и как ими пользоваться. Для этого мне надо напомнить основные принципы. Именно напомнить.

                                            У меня хватает ума не противопоставлять теорию и практику. Просто, по моему мнению, практика тоже должна присутствовать в университетских курсах. Иначе мы получаем кавалерию с представлением лишь о «шарообразных конях в вакууме». Нельзя верховой езде учить, рассказывая только о строении лошади и химическом составе овса.

                                              0
                                              > Если не секрет, какой курс читаете? Мне, действительно интересно.
                                              Базы данных.

                                              >О какой практике?
                                              О той, которую Вы даете.

                                              >Если в вашей компании удобнее брать людей, не знающих, что такое абстрактная фабрика, стратегия
                                              >или декоратор, то либо я неправильно понимаю направление вашей деятельности, либо у вас
                                              >достаточно времени и бюджета, чтобы этому обучать по ходу работы, на «живых» продуктах.
                                              Да, совершенно верно, от стажера нам ни разу не нужны знания об абстрактной фабрике, стратегии, декораторе, упаси байт, синглтоне или визиторе. Лучше, если у него их нет. За три месяца испытательного срока мы все равно научим его здесь лучше, чем в любом ВУЗе, и так как надо нам. Направление нашей деятельности — производство коробочного софта.

                                              >Моя задача — познакомить их с применением этого ООП на практике. В наиболее распространённых
                                              >случаях. Т.е. показать, что такое паттерны проектирования и как ими пользоваться. Для этого мне
                                              >надо напомнить основные принципы. Именно напомнить.
                                              Тогда я вообще не понимаю, зачем рассказы про машинки. Они рассчитаны на того, кто до этого ООП не знал вообще и дальше разбираться в нем особо не собирается.
                                                0
                                                >О какой практике?
                                                О той, которую Вы даете.

                                                Собственно, на этом можно дискуссию завершать, т.к. она всё-таки свелась к шарообразным коням в вакууме. К сожалению, про ту практику, «которую я даю» Вы категорично судите, имея о ней лишь отдалённое представление, почерпнутое из вступительных лекций. И мне разговор в таком ключе поддерживать абсолютно не хочется.

                                                Желаю удачи в подборе и обучении сотрудников.
                                                  0
                                                  >К сожалению, про ту практику, «которую я даю» Вы категорично судите, имея
                                                  >о ней лишь отдалённое представление, почерпнутое из вступительных лекций
                                                  Естественно. Более того, я сужу не о практике, а именно о лекциях — лекции на институтские не тянут ни при каком раскладе, уж извините.
                                                  Что же касается практики, то Вы о ней сами заговорили, напирая на то, что Вы исключительно практик, но вот как раз практики я здесь-то и не увидел.
                                    0
                                    нет, наследование — это когда мы берём готовый автомобиль и начинаем к нему приваривать дополнительные детали и менять существующие :-Р и хорошо получается только если эти модификации были предусмотрены изначально.
                                      0
                                      > Если не секрет, какой курс читаете? Мне, действительно интересно.
                                      Базы данных.

                                      >О какой практике?
                                      О той, которую Вы даете.

                                      >Если в вашей компании удобнее брать людей, не знающих, что такое абстрактная фабрика, стратегия
                                      >или декоратор, то либо я неправильно понимаю направление вашей деятельности, либо у вас
                                      >достаточно времени и бюджета, чтобы этому обучать по ходу работы, на «живых» продуктах.
                                      Да, совершенно верно, от стажера нам ни разу не нужны знания об абстрактной фабрике, стратегии, декораторе, упаси байт, синглтоне или визиторе. Лучше, если у него их нет. За три месяца испытательного срока мы все равно научим его здесь лучше, чем в любом ВУЗе, и так как надо нам. Направление нашей деятельности — производство коробочного софта.

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

                                          Потом случайно натолкнулся на этот автомобильный пример, потом на ваш и всё как-то встало на свои места ^__^.
                                          Огромное спасибо! Буду рекомендовать знакомым.

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

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