Эта статья продолжает цикл материалов об объектно-ориентированном программировании. Если вы ещё не ознакомились с введением в ООП, следует это сделать.
Как я уже писал во введении, разные языки программирования имеют более-менее общую основу в виде классов или объектов, а дальше начинается самодеятельность. Где-то применяется инкапсуляция, а где-то нет. Где-то поддерживается полиморфизм, а где-то нет. Из этого можно сделать вывод, что не все эти инструменты являются необходимыми. Ведь если их где-то нет, но люди все равно программируют на этих языках, значит можно обойтись и так.
Второй момент насчет дополнительных возможностей – они далеко не всегда нужны для того, чтобы писать какой-то особенный продвинутый код. Они нужны банально для того, чтобы людям, работая в команде, или работая над большим проектом, было проще организовать свою работу. Делать меньше ошибок, меньше тратить времени на сборку проекта, легче его поддерживать и т.д.
Абстрактные классы – это один из таких случаев. Сами по себе они не улучшат код вашей программы.
Суть абстрактного класса в том, что он недописан, и поэтому из него нельзя создать объект.
Недописан – это в буквальном смысле. Вы пишете класс, вы пишете методы в нём, но некоторые (или все) методы вы не дописываете. Вы пишете только их имя и всё. И помечаете их как abstract:
Как всегда, это запись не на каком-то конкретном языке, а только для иллюстрации.
Если класс абстрактный, то из данного класса невозможно создать объект. Ну приехали, а зачем тогда он? А затем, что можно отнаследоваться от этого класса и дописать то, что в нём не дописано. Например, отнаследуем класс Car:
И вот объект класса Car уже можно создать, потому что метод move() дописан до конца. Но что это всё-таки даёт? В общем-то ничего. Просто, создавая абстрактный класс Vehicle, вы ОБЯЗЫВАЕТЕ всех, кто будет от него наследоваться, дописать недописанные методы. Иначе не получится.
Если все ёще не очень понятно, повторю – дело тут не в заумном программировании, а в повышении дисциплины.
Как уже обсуждалось в статье про перезапись методов, мы могли бы создать обычный класс Vehicle с обычным методом move():
и отнаследовать от него класс Car, перезаписав метод move():
И получили бы тот же самый результат. В классе Car реализован свой собственный метод move(), какие проблемы?
Предположим, что когда вы писали класс Car, то забыли реализовать в нем метод move() – да, просто забыли. Но программа всё равно работает. Почему? Потому что Car наследует move() от родительского класса Vehicle. А вы об этом ничего не знаете до тех пор, пока что-то пойдёт не так.
Так вот абстрактный метод исключает такую ситуацию. Если вы забудете в Car реализовать метод move(), то ничего работать не будет, пока вы его не реализуете. Кроме того, из обычного класса Vehicle вы могли бы создать объект:
var v = new Vehicle();
Что тоже не всегда желательно, если Vehicle предназначен только для наследования от него. Абстрактный класс не позволит создать объект из себя. В общем, это не средство программирования, а средство принуждения к порядку.
В остальном абстрактные классы такие же, как обычные классы. Можно статически вызывать у них те методы, которые дописаны (т.е. не абстрактные), можно упоминать их при проверке типов.