Введение
Стиль объектно-ориентированного программирования, в котором наследование основано на классах.
Классное программирование, или, что более распространено, классная ориентация, — это стиль объектно-ориентированного программирования (ООП), в котором наследование осуществляется посредством определения классов объектов, а не посредством самих объектов (в отличие от прототипного программирования). Классная модель является наиболее популярной и развитой моделью ООП, в отличие от объектной модели. В этой модели объекты — это сущности, объединяющие состояние (т.е. данные), поведение (т.е. процедуры или методы) и идентичность (уникальное существование среди всех остальных объектов). Структура и поведение объекта определяются классом, который является определением или шаблоном для всех объектов конкретного типа. Объект должен быть явно создан на основе класса, и созданный таким образом объект считается экземпляром этого класса. Объект аналогичен структуре, но дополнен указателями на методы, контролем доступа к членам и неявным членом данных, который определяет местоположение экземпляров класса (т.е. объектов класса) в иерархии классов (что необходимо для функций наследования во время выполнения).
Инкапсулирование
Инкапсуляция предотвращает нарушение пользователями инвариантов класса, что полезно, поскольку позволяет изменять реализацию класса объектов в части аспектов, не представленных в интерфейсе, без влияния на пользовательский код. Определения инкапсуляции акцентируют внимание на группировке и объединении связанных данных (сплоченности), а не на вопросах безопасности.
Наследие
В объектно-ориентированном программировании наследование реализуется путем определения новых классов как расширений существующих: существующий класс является базовым классом, а новый – производным классом. Если производный класс имеет только один базовый класс, это называется одиночным наследованием, а если производный класс может иметь несколько базовых классов, это называется множественным наследованием. Это организует классы в иерархию, в виде дерева (при одиночном наследовании) или решетки (при множественном наследовании). Ключевой особенностью наследования является то, что наследуются как интерфейс, так и реализация; если наследуется только интерфейс, это называется наследованием интерфейса или подтипированием. Наследование также может быть реализовано без использования классов, как, например, в прототипном программировании.
Критика
Языки, основанные на классах, или, точнее, типизированные языки, где подклассификация является единственным способом подтипирования, критикуются за смешение реализации и интерфейсов — основополагающий принцип объектно-ориентированного программирования. Критики утверждают, что можно создать класс «мешок», хранящий коллекцию объектов, а затем расширить его для создания нового класса «множество», в котором исключено дублирование объектов. Теперь функция, принимающая объект класса «мешок», может ожидать, что добавление двух объектов увеличит размер мешка на два, однако если передать объект класса «множество», то добавление двух объектов может как увеличить, так и не увеличить размер мешка на два. Проблема возникает именно потому, что подклассификация подразумевает подтипирование даже в тех случаях, когда принцип подтипирования, известный как принцип подстановки Лисков, не выполняется. Барбара Лисков и Джанетт Уинг сформулировали этот принцип в своей работе 1994 года следующим образом:
Требование к подтипу: пусть \phi(x) — свойство, доказуемое для объектов x типа T. Тогда \phi(y) должно быть истинным для объектов y типа S, где S является подтипом T.
Таким образом, обычно необходимо различать подтипирование и подклассификацию. Большинство современных объектно-ориентированных языков различают подтипирование и подклассификацию, однако некоторые подходы к проектированию этого не делают. Другой распространенный пример: объект «человек», созданный из дочернего класса, не может стать объектом родительского класса, поскольку дочерний и родительский классы наследуют класс «человек», но языки, основанные на классах, в основном не позволяют изменять тип класса объекта во время выполнения. Для языков, основанных на классах, это ограничение необходимо для сохранения единого представления о классе для его пользователей. Пользователям не нужно беспокоиться о том, что одна из реализаций метода может привести к изменениям, нарушающим инварианты класса. Такие изменения можно внести, уничтожив объект и создав новый на его месте. Полиморфизм можно использовать для сохранения соответствующих интерфейсов даже при таких изменениях, поскольку объекты рассматриваются как абстракции «черного ящика» и к ним обращаются через идентификатор объекта. Однако обычно изменяется значение ссылок на объект, что оказывает влияние на клиентский код.
Примеры языков
Хотя Simula представила абстракцию класса, Smalltalk является каноническим примером языка, основанного на классах. К другим языкам относятся PHP, C++, Java, C# и Objective-C.