Абстракция в Java
Читаю про ООП и там сказано , что у ООП есть 3 основных основных понятия. Это инкапсуляция, полиморфизм и наследование. Так же сказано , что к ним еще можно отнести абстракцию. Про первые три понятия я понял , а вот про абстракцию что то вообще ничего не пойму. Можете на каком то понятном примере объяснить , что такое абстракция в ООП ? (Книга : «ОО Анализ и Проектирование» , Гради Буч ). У первых трех понятий есть конкретное применение в языке , а про абстракцию читаю только в теории и не пойму зачем она и какой в ней смысл ?
Отслеживать
1,552 2 2 золотых знака 10 10 серебряных знаков 17 17 бронзовых знаков
задан 5 дек 2013 в 15:06
521 2 2 золотых знака 10 10 серебряных знаков 23 23 бронзовых знака
5 дек 2013 в 21:55
4 ответа 4
Сортировка: Сброс на вариант по умолчанию
Отличный вопрос! чтобы понять, что такое Абстракция можно почитать пару статей из интернета (один, два).
Но по сути достаточно запомнить следующее:
(абстракция будет возрастать с каждым пунктом)
1) instance (Объект) сущность обладающая набором характеристик свойственных конкретному экземпляру класса. Имеет конкретные значения полей (низший уровень, без абстракции)
2) class (класс) описание множества объектов схожих по свойствам и внутренней структуре (шаблон для создания объектов).
3) abstract class (Абстрактный класс) — абстрактное описание характеристик множества классов (выступает как шаблон для наследования другими классами). Имеет высокий уровень абстракции, в связи с чем, от абстрактного класса нельзя создавать объекты напрямую* (только через создание объектов от классов наследников)
Внутри абстрактного класса могут присутствовать методы с реализацией (но не обязательно)
4) interface (Интерфейс) — это конструкция языка программирования Java, в рамках которой могут описываться только абстрактные публичные методы (abstract public) и статические константы свойства (final static). То есть также, как и на основе абстрактных классов, на основе интерфейсов нельзя порождать объекты.
upd: Начиная с Java 8 кроме абстрактных методов и констант мы также можем использовать в интерфейсах стандартные методы (default methods) и статические методы (static methods).
немного о реализации:
классы в java не поддерживают множественное наследование(это касается и абстрактных классов), поэтому могут наследоваться (напрямую), лишь от одного родителя:
class Имя_класса_наследника extends Имя_класса_родителя < // реализация >
за-то класс может реализовывать множество интерфейсов
class Имя_класса implements интерфейс_1, интерфейс_2, . ,интерфейс_N < // реализация методов интерфейсов // и реализация собственных методов >
Один интерфейс может быть наследником (может расширяться) нескольких интерфейсов:
interface интерфейс_1 extends интерфейс_2, интерфейс_3, . , интерфейс_N < //описание методов и полей для интерфейс_1 //также методов и поля будут взяты из интерфейсов интерфейс_2 . интерфейс_N >
Классы могут реализовывать интерфейсы (т. е. получать от интерфейса список методов и описывать реализацию каждого из них), притом, что особенно важно, один класс может реализовывать сразу несколько интерфейсов:
class Имя_класса implements интерфейс_1, интерфейс_2, . ,интерфейс_N < // реализация методов интерфейсов // и реализация собственных методов >
Класс может напрямую наследовать свойства и методы, только от одного родительского класса (extends), и одновременно с этим, он может реализовывать множество интерфейсов (implements):
class Имя_класса extends Имя_класса_2 implements интерфейс_1,интерфейс_2. интерфейс_N < // реализация методов интерфейсов // реализация собственных методов // переопределение методов родительского класса >
Вывод: так как интерфейс схож с абстрактным классом, но позволяет (неявно) выполнить множественное расширение — он имеет максимальный уровень Абстракции
Абстрактный класс в Java
Привет! Это статья про абстрактный класс в Java, а также об абстрактных методах. Это не самая простая тема, потому что она, ну. слегка абстрактная Поэтому читайте внимательно!
Что такое абстрактный класс
Вы наверняка уже знакомы с понятием класса. Если нет, почитайте эту статью:
Обычно мы создаем классы для того, чтобы пользоваться их объектами. Например, мы создаем объекты типа String, или Scanner, или FileWriter для дальнейшей работы.
Тем не менее, объекты классов нам нужны не всегда. Иногда нам просто нужен суперкласс (т.е. класс, который мы будем наследовать), в котором будут задаваться какие-то общие для наследников методы и характеристики.
Представим, что у нас есть три типа животных:
1. Cобака (класс Dog)
2. Кошка (класс Cat)
3. Корова (класс Cow)
Все это животные — и поэтому мы можем создать один общий для всех суперкласс Animal, в котором разом задаем общие методы для всех трех подклассов.
Тем не менее, можно сказать что объект именно класса Animal нам не пригодится — более того, логически его не может существовать. Ведь существует животное кошка, животное собака — но животное «животное» не существует.
Или, например, представим что Вы пишете игру, где есть разные навыки и оружие.
По навыкам, допустим, Ваш персонаж может:
3. Делать двойне сальто
Это все навыки: навык «красться», навык «бежать». Но навыка «навык» не существует. Верно?
По оружию, допустим, в игре есть такие опции:
3. Двуручный меч
И кинжал, и арбалет, и меч — это оружие. Но оружия «оружие» не существует. Верно?
Я думаю Вы поняли Так вот, именно такой класс — т.е. класс «без объектов»- и называется абстрактным.
Как выглядит абстрактный класс
Создать абстрактный класс очень просто. Просто перед словом «class» нужно дописать «abstract«:
Давайте посмотрим на примере. Создадим класс MyClass (пока без «abstract«):
Что такое абстракция в java
Абстрактные классы vs интерфейсы в Java
Различия между абстрактными классами и интерфейсами в Java
В процессе профессионального развития каждого начинающего программиста всегда наступает тот момент, когда требуется понять и осознать разницу между интерфейсом и абстрактным классом. Ясно представлять себе границы их использования, а также уметь выбирать, что из этого лучше применить в том или ином месте кода.
Кроме того, обсуждаемый в данной статье вопрос о различиях, является одним из самых распространенных на собеседованиях, на который зачастую отвечают либо неполно, либо неверно.
Почему же на этот вопрос отвечают неправильно? Дело в том, что Java развивается, и границы отличий между абстрактным классом и интерфейсом постепенно стираются. А новички, читая устаревшие книги по Java (или не читая их вовсе) или даже современные статьи-перепечатки, где рассказывается об интерфейсах до Java 8, не имеют представления о том, что в своем развитии они ушли далеко вперед.
Например, до появления Java 8, при возникновении вопроса на собеседовании типа: «Назовите разницу между абстрактным классом и интерфейсом», вы смело могли сказать, что интерфейс представляет собой контракт, содержащий методы без реализации, которые должны быть реализованы в классах, имплементирующих этот интерфейс. А абстрактный класс — это класс, который содержит (или не содержит) абстрактные методы и общий для его потомков код.
Также раньше вы могли сказать, что интерфейс не может содержать статические, приватные или методы по умолчанию, и что в нем вообще не может быть реализовано никакой логики. В техническом плане все ограничения остались в прошлом — граница между этими понятиями сейчас уже почти стерта. Но с фундаментальной точки зрения ничего не изменилось!
В данной статье будут рассмотрены как фундаментальные, так и технические различия между интерфейсом и абстрактным классом.
1. Фундаментальное отличие
Фундаментальная разница между интерфейсом и абстрактным классом заключается в том, что интерфейс определяет только поведение. Он не сообщает ничего про объект, который будет его реализовывать.
Например, такое поведение как «движение» может быть применимо к разным типам объектов: машина, кот, котировки курса и т. д. Эти объекты не имеют ничего общего, кроме того, что они могут двигаться.
Перефразируем немного иначе — если существует «движущийся» объект, то глядя на реализованный им интерфейс, мы не сможем понять, какой именно тип объекта имеется ввиду. Это может быть машина, кот, котировка курса валют и много других вариантов.
Если перенести это поведение в код, написанный на языке Java, то получится следующее:
interface Movable
Абстрактный же класс описывает некий абстрактный объект (автомобиль, человека, кота и т. д.), а не только поведение.
Если мы рассуждаем про абстрактный «автомобиль», то в нашей голове сразу формируется картинка с объектом. Мы сразу понимаем, что автомобиль содержит двигатель, колеса и может двигаться, поворачивать, ускоряться или тормозить. Он также будет иметь поля для хранения внутренних деталей, таких как мотор, колеса и тормоза. Вы получите все это просто сказав слово «автомобиль».
При этом кот и котировка курса валют не могут быть автомобилем, даже если они также могут двигаться.
На основе вышесказанного создадим класс Automobile:
abstract class Automobile
Интерфейс и абстрактный класс — понятия не взаимозаменяемые. Даже если абстрактный класс с абстрактными методами выглядит подобно интерфейсу, а интерфейс, с его методами по умолчанию, подобен абстрактному классу с методами, имеющими реализации, то это все равно будут два фундаментально разных понятия. Если нам нужно поведение — необходимо использовать интерфейс. Если речь про концептуальный объект — мы должны использовать абстрактный класс.
А теперь поговорим про различия в технической реализации.
2. Технические отличия
В этом разделе мы обсудим технические (синтаксические) различия в реализации этих концепций в Java. Именно так обычно отвечают на вопрос о разнице между интерфейсами и абстрактными классами (но мы-то уже знаем, что это только вторая часть ответа, и при этом не главная).
2.1. Синтаксис создания
Итак, при создании абстрактного класса указывается ключевое слово abstract, а при определении интерфейса — interface.
Пример абстрактного класса:
public abstract class MyAbstractClass < // поля и конструкторы // абстрактные методы // методы с реализацией >
Пример интерфейса:
public interface MyInterface < // объявление констант // методы без реализации // статические методы // методы по умолчанию (default) // приватные методы >
2.2 Синтаксис использования
При наследовании от абстрактного класса используется ключевое слово extends (с англ. «расширяет»), а при реализации интерфейса — implements (с англ. «реализует»).
В приведенном ниже коде класс MyClass расширяет MyAbstractClass:
public class MyClass extends MyAbstractClass < // реализация абстрактных методов // иной код >
А тут класс MyClass реализует интерфейс MyInterface:
public class MyClass implements MyInterface < // реализация методов интерфейса // иной код >
Класс может одновременно и наследоваться от абстрактного класса (только одного) и реализовать один или множество интерфейсов.
Например, класс MyClass реализует интерфейс MyInterface, MyInterface_2 и MyInterface_3:
class MyClass extends MyAbstractClass implements MyInterface, MyInterface_2, MyInterface_3 < // реализация абстрактных методов абстрактного класса // реализация методов из интерфейсов // иной код >
2.3 Наличие конструктора
Как вы знаете, невозможно создать экземпляр абстрактного класса. Но, объявить и определить в нем конструктор мы можем. В противном случае за нас это сделает компилятор, создав конструктор по умолчанию. Без него код просто не скомпилируется, поскольку при создании конкретного класса первым оператором будет неявный вызов super() конструктора суперкласса, в данном случае абстрактного.
Добавим в абстрактный класс MyAbstractClass конструктор:
public abstract class MyAbstractClass < public MyAbstractClass() < System.out.println("Конструктор из MyAbstractClass"); >>
Также добавим конструктор в MyClass:
public class MyClass extends MyAbstractClass < public MyClass() < System.out.println("Конструктор из MyClass"); >>
В классе Main создадим объект и запустим программу:
public class Main < public static void main(String[] args) < MyAbstractClass myObject = new MyClass(); >>
Результат выполнения программы:
Для интерфейсов понятия «конструктор» не существует.
2.4 Типы переменных
Все переменные в интерфейсах неявно являются public static final (т.е. константами). «final» подразумевает, что переменной обязательно должно быть присвоено значение во время инициализации.
Рассмотрим следующий код:
public interface MyInterface < // эта строка не скомпилируется int value_1; int value_2 = 1; public final int value_3 = 1; static int value_4 = 1; public final static int value_5 = 1; static final int value_6 = 1; >
Поскольку value _1 не присвоено конкретное значение, а она является неявно final, код с такой строкой не скомпилируется. Остальные строки не вызовут ошибок, т.к. public static final можно не указывать (если указать, то IDE выделит их серым цветом, подчеркивая «избыточность»).
В абстрактных классах переменные могут быть любыми — абстрактность класса не накладывает ограничений.
Например, следующий код является корректным:
public abstract class MyAbstractClass
2.5 Модификаторы доступа методов
Модификаторы доступа для абстрактных классов могут быть любыми. При этом, все методы, кроме абстрактных, должны иметь реализацию.
А вот в случае с интерфейсами модификаторы доступа могут быть только двух типов, public и private (последний — начиная с Java 9).
Причем private может быть применим только к методам, имеющим реализацию, которые, в свою очередь, могут использоваться только методами по умолчанию, находящимися в интерфейсе. Класс, реализующий интерфейс, не будет иметь к ним доступ. Методы интерфейса без реализации являются неявно public, поэтому этот модификатор можно не писать.
Рассмотрим следующий код:
public interface MyInterface_2 < void publicAbstractMethod_1(); public void publicAbstractMethod_2(); void publicAbstractMethod_3(); private void privateMethod() < // Реализация метода >>
Методы publicAbstractMethod_1 и publicAbstractMethod_3 являются неявно public.
2.6 Методы с реализацией
Для абстрактного класса все методы, кроме абстрактных, должны иметь реализацию.
Для интерфейсов, начиная с Java 8, вводится понятие метода по умолчанию. Такие методы, во-первых, должны иметь реализацию в интерфейсе, а во-вторых, помечены ключевым словом default. Они также являются неявно public. При этом они не должны в обязательном порядке иметь реализацию в реализующем интерфейс классе, но могут быть в нем переопределены.
Также, начиная с Java 8, в интерфейсах допустимы статические методы, которые неявно являются public, но могут быть явно private. Т. е. если указать модификатор доступа private, метод будет приватным, а если ничего не указывать, то публичным.
Например, код ниже скомпилируется:
public interface MyInterface_3 < default void defaultMethod() < // Реализация метода >public default void defaultMethod_2() < // Реализация метода >private static void privateStaticMethod() < // Реализация метода >public static void publicStaticMethod_1() < // Реализация метода >static void publicStaticMethod_2() < // Реализация метода >>
2.7 Наследование
Интерфейс не может реализовывать интерфейс, не может наследовать абстрактный класс, но может наследовать (используя ключевое слово extends) множество других интерфейсов.
Абстрактный класс может наследовать как обычный класс, так и абстрактный. В обоих случаях это будет только один класс (в Java нет множественного наследования классов).
В то же время абстрактный класс также может реализовать до 65 535 интерфейсов (это связано с ограничением константы interfaces_count в структуре ClassFile).
В этом месте давайте немного отойдем от темы сравнения и затронем множественное наследование. В некоторых источниках однозначно указывается, что множественного наследования в Java нет. В других источниках говорится, что множественного наследования как бы нет, но оно реализуется через интерфейсы.
- наследование состояния (Inheritance of State)
- наследование реализации (Inheritance of Implementation)
- наследование типа (Inheritance of Type)
Java не поддерживает множественное наследование состояния, но поддерживает множественное наследование реализации (как вариант, на основе методов по умолчанию от интерфейсов). Она также поддерживает множественное наследование типов (поскольку может реализовать более одного интерфейса).
Именно таким должен быть ответ на вопрос о множественном наследовании в Java.
3. Рекомендации к применению абстрактных классов и интерфейсов
В соответствии с рекомендациями Oracle абстрактный класс нужно использовать в следующих случаях:
- Необходимо выделить общий код между несколькими тесно связанными классами
Пояснение: это типовой рефакторинг, целью которого является устранение дублирования кода.
- Мы ожидаем, что классы, расширяющие абстрактный класс, имеют много общих методов, полей или требуют модификаторов доступа, отличных от public (protected и private)
Пояснение: ранее мы писали, что в интерфейсах методы, имеющие реализацию (помеченные ключевым словом default), являются неявно public. Если же метод, имеющий реализацию, помечен явно как private, то он не сможет быть использован в классах, реализующих этот интерфейс, а только в других методах интерфейса. Поэтому, если нам нужны методы с модификаторами доступа не public, мы должны использовать абстрактный класс.
- Мы хотим объявить не static или не final поля для изменения состояния объекта.
Пояснение: ранее мы писали, что все переменные в интерфейсах неявно являются public static final — из-за чего они не могут быть изменены.
Для использования интерфейсов существуют следующие причины:
- Планируется, что несвязанные между собой классы будут реализовывать интерфейс. Например, интерфейсы Comparable и Cloneable реализуются многими несвязанными между собой классами.
Пояснение: как мы выяснили ранее, концептуальное назначение интерфейса — описание «поведения», а не «состояния» (в отличие от абстрактного класса). Соответственно, реализовать это поведение могут любые классы, несвязанные между собой, которые просто должны что-то «уметь» делать или «как-то» себя вести.
- Требуется детализировать или определить поведение определенного типа данных, но при этом мы не хотим беспокоиться о том, кто реализует его поведение.
Пояснение: пояснение к прошлому пункту также актуально и для этого — нам все равно, какие классы будут реализовывать наш интерфейс и в каких пакетах находятся. Мы просто хотим, чтобы они вели себя в соответствии с «нашим контрактом», прописанным в интерфейсе в виде методов без реализации.
- Мы хотим воспользоваться преимуществами множественного наследования типов
Приведем наглядный пример выбора между абстрактным классом и интерфейсом.
Существует паттерн «Шаблонный метод», определение которого звучит так: «шаблонный метод определяет основу алгоритма и позволяет подклассам переопределить некоторые его шаги, не изменяя структуру, в целом».
Суть паттерна заключается в размещении в абстрактном классе метода с реализацией, в котором вызываются абстрактные методы. Далее подклассы абстрактного класса реализуют их каждый по-своему.
Так вот вопрос, а что нам мешает разместить абстрактные и шаблонные методы в интерфейсе? В качестве шаблонного метода мы могли бы использовать метод по умолчанию. Вроде звучит логично, согласитесь?
Но обратите еще раз внимание на определение шаблонного метода. Там есть такие слова: «… не изменяя структуру, в целом». Подклассы абстрактного класса не должны иметь возможность переопределить шаблонный метод с целью изменения логики (алгоритма) его работы. По этой причине шаблонные методы объявляются как final и не могут использовать интерфейсы с их методами по умолчанию (могут быть переопределены) вместо абстрактных классов. Вся идея паттерна в этом случае будет нарушена.
Для того чтобы рассмотреть разницу между интерфейсом и абстрактным классом немного глубже, рекомендуется обратиться к книге «Java. Эффективное программирование», Блох Д., 3-е издание.
В разделе 4.6 этой книги говорится о следующих причинах предпочтения интерфейсов абстрактным классам:
1. Существующие классы можно легко приспособить для реализации нового интерфейса.
Пояснение: для этого достаточно написать implements и реализовать необходимые методы. Но уже имеющиеся классы в общем случае не могут быть переделаны для расширения нового абстрактного класса. Если вы хотите, чтобы два класса расширяли один и тот же абстрактный класс, вам придется поднять этот класс в иерархии настолько высоко, чтобы он стал предком обоих этих классов. Это может привести к нарушению логики иерархии типов, заставляя всех потомков нового абстрактного класса расширять его независимо от того, насколько это целесообразно.
2. Интерфейсы идеально подходят для создания миксинов.
Пояснение: Миксин (mixin) — это тип, который класс может реализовать в дополнение к своему «первичному типу», объявляя о том, что этот класс предоставляет некоторое необязательное поведение. Например, Comparable является таким интерфейсом-миксином, т. к. добавляет (примешивает) к первоначальным возможностям типа дополнительную функциональность.
Использовать абстрактные классы для создания миксинов нельзя по той же причине, по которой их невозможно приспособить к уже имеющимся классам: класс не может иметь больше одного родителя, и в иерархии классов нет подходящего места, куда можно поместить миксин.
3. Интерфейсы позволяют создавать неиерархические каркасы типов.
Пояснение: иерархии типов прекрасно подходят для организации некоторых сущностей, но зато сущности других типов невозможно аккуратно уложить в строгую иерархию. Альтернативой им является раздутая иерархия классов.
4. Интерфейсы обеспечивают безопасное и мощное развитие функциональности с использованием шаблона «Декоратор». Паттерн «Декоратор» позволяет динамически (в ходе выполнения программы) добавлять объекту новые возможности (состояние и/или поведение) на основе композиции.
Концепции объектно-ориентированного программирования JAVA
JAVA основывается на концепциях объектно-ориентированного программирования, что позволяет перейти на более высокий уровень абстракции, чтобы разрешить любую проблему реалистичным путем. Объектно-ориентированный подход концептуализирует решение проблемы в плоскости объектов реального мира, которые легче повторно использовать в приложении. Например, Chair (стул), Fan (вентилятор), Dog (Собака), Computer (компьютер) и так далее. В JAVA класс представляет собой макет, шаблон или прототип, который определяет общее поведение объекта данного типа. Экземпляр — это отдельная реализация класса, и все экзепляры класса имеют одинаковые свойства, которые описаны в определении класса. Например, вы можете опрделить класс с именем House (дом) с количеством комнат в качестве атрибута и создать экземпляры класса, такие как дом с двумя комнатами, дом с тремя комнатами и так далее.Преимущества: Ниже перечислены некоторые плюсы объектно-ориентированной разработки программного обеспечения (ПО).
- Снижение затрат на поддержку ПО, в основном за счет того, что она осуществляется модульно.
- Усовершенствованное повторное использование кода благодаря таким качествам, как наследование, и, как результат, более быстрая разработка ПО.
- Повышенные надежность и гибкость кода.
- Легкость понимания вследствие моделирования реального мира.
- Лучшая абстракция на уровне объекта.
- Уменьшение сложности перехода от одной фазы разработки к другой.
Есть четыре основные характеристики ООП:
- Инкапсуляция
- Наследование
- Полиморфизм
- Абстракция
Инкапсуляция
- Мы можем защитить внутреннее состояние объекта с помощью сокрытия его атрибутов.
- Это улучшает модульное построение кода, так как предотвращает взаимодействие объектов неожиданными способами.
- Повышается практичность кода.
- Это поддерживает договорные отношения конкретного объекта.
- Инкапсуляция облегчает поддержку ПО.
- Изменения в коде могут производиться независимо друг от друга.
Полиморфизм
Полиморфизм в программировании — это способность предоставлять один и тот же интерфейс для различных базовых форм (типов данных). Это означает, что классы, имеющие различную функциональность, совместно используют один и тот же интерфейс и могут быть динамически вызваны передачей параметров по ссылке. Классический пример — это класс Shape (фигура) и все классы, наследуемые от него: square (квадрат), circle (круг), dodecahedron (додекаэдр), irregular polygon (неправильный многоугольник), splat (клякса) и так далее. В этом примере каждый класс будет иметь свой собственный метод Draw() и клиентский код может просто делать:
Shape shape = new Shape();
- Создание повторно используемого кода. То есть, как только класс создан, реализован и протестирован, он может свободно использоваться без заботы о том, что конкретно в нем написано.
- Это обеспечивает более универсальный и слабосвязанный код.
- Понижается время компиляции, что ускоряет разработку.
- Динамическое связывание.
- Один и тот же интерфейс может быть использован для создания методов с разными реализациями.
- Вся реализация может быть заменена с помощью использования одинаковых сигнатур метода.
while(it.hasNext()) < Shape s = (Shape) it.next(); totalArea += s.area(dim); //будет применен полиморфизм и вызван нужный метод для каждого объекта. >
Перезагрузка методов или ad-hoc полиморфизм или статический полиморфизм Перезагрузка взаимодействует с несколькими методами одного класса, которые одинаково названы, но имеют разные сигнатуры методов. Перезагрузка позволяет вам описать одну и ту же операцию различными путями для разных данных. Иногда ее называют статическим полиморфизмом, но фактически полиморфизмом она не является. Это ничто иное, как просто наличие двух методов с одинаковыми именами, но разным списком аргументов. Перезагрузка не имеет ничего общего с наследованием и полиморфизмом. И перезагруженный метод совсем не то же самое, что переопределенный метод. Параметрический полиморфизм через обобщение в JAVA При объявлении класса поле имени может ассоциироваться с различными типами, а имя метода может ассоциироваться с различными параметрами и возвращаемыми типами. JAVA поддерживает параметрический полиморфизм, применяя обобщение (дженерики).
List list = new ArrayList();
Почему мы не можем переопределить статический метод в JAVA? Переопределение зависит от наличия экземпляра класса. Идея полиморфизма состоит в том, что вы можете создать подкласс, и объекты, реализуемые теми подклассами, будут вести себя по-другому с теми же методами родителького класса (переопределенными в подклассах). Статический метод не ассоциируется ни к каким экземпляром класса, таким образом, сама концепция переопределения не может быть применена. Создателями JAVA руководили два соображения, которые повлияли на такой подход. Во-первых, это проблемы исполнения кода: лилось очень много критики в адрес Smalltalk из-за медленной работы (сборщик мусора и полиморфизм были частью этой проблемы), и в проектировании JAVA старались этого избежать. Вторым соображением было решение, что целевой аудиторией JAVA станут С++ разработчики. То, что статические методы работают именно таким образом, было очень знакомо C++ программистам, а так же ускоряло работу, так как не было необходимости проходить вверх по иерархии классов, чтобы выяснить, какой метод вызывать. Вы идете прямо к классу и вызываете конкретный метод.
Наследование
- Усовершенствованное повторное использование кода.
- Устанавливается логическое отношение «is a» (является кем-то, чем-то). Например: Dog is ananimal. (Собака является животным).
- Модуляризация кода.
- Исключаются повторения.
- Сильная связанность: подкласс зависит от реализации родительского класса, что делает код сильно связанным.
Абстракция
- Применяя абстракцию, мы можем отделить то, что может быть сгруппировано по какому-либо типу.
- Часто изменяемые свойства и методы могут быть сгруппированы в отдельный тип, таким образом основной тип не будет подвергаться изменениям. Это усиливает принцип ООП: «Код должен быть открытым для Расширения, но закрытым для Изменений».
- Абстракция упрощает представление доменных моделей.
- Множественное наследование.
- Слабая связанность. Происходит абстракция операции, такая как разделение на уровни, а конкретной реализацией может быть что угодно: JDBC, JPA, JTA и т.д.
- Программа-интерфейс не реализуется.
- Полиморфизм с динамическим связыванием: раскрывается програмный интерфейс объекта без раскрытия его фактической реализации.
- Абстрактные уровни, разделение функциональностей.
- Интерфейс — это договорные отношения с классами, которые этот интерфейс реализуют, о том, что реализация происходит путём, обозначенным интерфейсом. Это пустая оболочка с объявленными методами.
- Абстрактный класс определяет некоторое общее поведение и просит свои подклассы определить нетипичное или конкретное поведение для своего класса.
- Методы и члены абстрактного класса могут быть обозначены любым модификатором доступа, в свою очередь все методы интерфейса обязаны быть открытыми (public).
- Когда происходит наследование абстрактного класса, класс-наследник должен определить абстрактные методы, в то время как интерфейс может наследовать другой интерфейс и при этом не обязательно определять его методы.
- Класс-наследник может расширять только один абстрактный класс, а интерфейс может расширять или класс может реализовывать множество других интерфейсов.
- Класс-наследник может определять абстрактные методы с тем же или менее ограниченным модификатором доступа, при этом класс, реализующий интерфейс, должен определять методы с тем же уровнем видимости.
- Интерфейс не содержит конструкторы, в том время, как они есть в абстрактном классе.
- Переменные, объявленные в Java-интерфейсе по умолчанию являются final. Абстрактный класс может содержать переменные, которые не являются final.
- Все участники Java-интерфейса по умолчанию являются public . Участники абстрактного класса могут позволить себе быть public , protected и др.
Композиция
- Контроль видимости
- Реализация может быть заменена во время выполнения (run-time)
- Слабая связанность, так как класс-интерфейс не зависит от реализации.
№ | Композиция (has a / имеет) | Наследование (is a / является) |
---|---|---|
1 | Поддерживает полиморфизм и повторное использование кода. | Поддерживает полиморфизм и повторное использование кода. |
2 | Объект во время выполнения (run-time) уже создан. | Объект создается динамически во время компиляции. |
3 | Реализация может быть заменена во время выполнения (run-time). | Реализация может быть заменена во время компиляции. |
4 | Подкласс не зависит от класса-родителя, что благоприятствует слабому связыванию (особенно под управлением интерфейса). | Подкласс завизист от реализации класса-родителя, поэтому связывание считается сильным. |
5 | Использование: в Доме есть Ванная комната. Неправильно говорить, что Дом — это Ванная комната. | Наследование является однонаправленным: Дом — это Здание. Но здание не является домом. |
Примечание: Не используйте наследование только для того, чтобы обеспечить повторное использование кода. Если нет отношенией “is a“ (является), для этих целей используется композиция. Разница между композицией и агрегацией в отношениях объектов. Агрегация — это взаимосвязь, при которой один класс вписывается в коллекцию. Это часть целого отношения, где часть может существовать без целого. Такие отношения гораздо слабее. Нет циклической зависимости. Например: заказ и продукт. Композиция — это взаимосвязь, при которой один класс вписывается в коллекцию. Это часть целого отношения, при которой часть не может существовать без целого. Если целое уничтожается, все его составляющие тоже будут уничтожены. Это более сильные отношения. Например: многоугольник и его вершины, заказ и его компонент.