From a4d9c3ca38a6bcf137897ecb4991d94b268832f1 Mon Sep 17 00:00:00 2001 From: Arthur Date: Tue, 3 Mar 2020 18:29:47 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D1=8B=20=D0=BF=D1=80=D0=B8=D0=BC=D0=B5=D1=80=D1=8B=20?= =?UTF-8?q?=D0=BA=20=D0=B4=D0=BE=D0=BA=D1=83=D0=BC=D0=B5=D0=BD=D1=82=D0=B0?= =?UTF-8?q?=D1=86=D0=B8=D0=B8=20=D0=9E=D0=9E=D0=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- oop.md | 217 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 217 insertions(+) diff --git a/oop.md b/oop.md index cdc2afb..0a57397 100644 --- a/oop.md +++ b/oop.md @@ -48,6 +48,37 @@ __Инкапсуляция__ – это свойство системы, поз >Теперь вернёмся в сегодняшний день к современным чудесам автопрома с коробкой-автоматом. На самом деле, по сути, ничего не изменилось. Бензонасос всё так же поставляет бензин в двигатель, дифференциалы обеспечивают поворот колёс на различающиеся углы, коленвал превращает поступательное движение поршня во вращательное движение колёс. Прогресс в другом. Сейчас все эти действия скрыты от пользователя и позволяют ему крутить руль и нажимать на педаль газа, не задумываясь, что в это время происходит с инжектором, дроссельной заслонкой и распредвалом. Именно сокрытие внутренних процессов, происходящих в автомобиле, позволяет эффективно его использовать даже тем, кто не является профессионалом-автомехаником с двадцатилетним стажем. Это сокрытие в ООП носит название инкапсуляции. +Пример: +```java +public class SomePhone { + + private int year; + private String company; + public SomePhone(int year, String company) { + this.year = year; + this.company = company; + } + private void openConnection(){ + //findComutator + //openNewConnection... + } + public void call() { + openConnection(); + System.out.println("Вызываю номер"); + } + + public void ring() { + System.out.println("Дзынь-дзынь"); + } + +} +``` +Модификатор private делает доступными поля и методы класса только внутри данного класса. Это означает, что получить доступ к private полям из вне невозможно, как и нет возможности вызвать private методы. + +Сокрытие доступа к методу openConnection, оставляет нам также возможность к свободному изменению внутренней реализации этого метода, так как этот метод гарантированно не используется другими объектами и не нарушит их работу. + +Для работы с нашим объектом мы оставляем открытыми методы call и ring с помощью модификатора public. Предоставление открытых методов для работы с объектом также является частью механизма инкапсуляции, так как если полностью закрыть доступ к объекту – он станет бесполезным. + [к оглавлению](#ООП) ## Что такое _«наследование»_? @@ -61,6 +92,56 @@ __Наследование__ – это свойство системы, поз >Очевидно, что все три модификации будут иметь большинство свойств прежней модели (старый добрый двигатель 1970 года, непробиваемая ходовая часть, зарекомендовавшая себя отличным образом на отечественных дорогах, коробку передач и т.д.). При этом каждая из моделей будет реализовать некоторую новую функциональность или конструктивную особенность. В данном случае, мы имеем дело с наследованием. +Пример: +Рассмотрим пример создания класса смартфон с помощью наследования. Все беспроводные телефоны работают от аккумуляторных батарей, которые имеют определенный ресурс работы в часах. Поэтому добавим это свойство в класс беспроводных телефонов: +```java +public abstract class WirelessPhone extends AbstractPhone { + + private int hour; + + public WirelessPhone(int year, int hour) { + super(year); + this.hour = hour; + } +} +``` +Сотовые телефоны наследуют свойства беспроводного телефона, мы также добавили в этот класс реализацию методов call и ring: +```java +public class CellPhone extends WirelessPhone { + public CellPhone(int year, int hour) { + super(year, hour); + } + + @Override + public void call(int outputNumber) { + System.out.println("Вызываю номер " + outputNumber); + } + + @Override + public void ring(int inputNumber) { + System.out.println("Вам звонит абонент " + inputNumber); + } +} +``` +И, наконец, класс смартфон, который в отличие от классических сотовых телефонов имеет полноценную операционную систему. В смартфон можно добавлять новые программы, поддерживаемые данной операционной системой, расширяя, таким образом, его функциональность. С помощью кода класс можно описать так: +```java +public class Smartphone extends CellPhone { + + private String operationSystem; + + public Smartphone(int year, int hour, String operationSystem) { + super(year, hour); + this.operationSystem = operationSystem; + } + + public void install(String program){ + System.out.println("Устанавливаю " + program + "для" + operationSystem); + } + +} +``` +Как видите, для описания класса Smartphone мы создали совсем немного нового кода, но получили новый класс с новой функциональностью. Использование этого принципа ООП java позволяет значительно уменьшить объем кода, а значит, и облегчить работу программисту. + [к оглавлению](#ООП) ## Что такое _«полиморфизм»_? @@ -79,6 +160,112 @@ _Полиморфная переменная_, это переменная, ко + _ad hoc_, функция ведет себя по разному для разных типов аргументов (например, функция `draw()` — рисует по разному фигуры разных типов); + _параметрический_, функция ведет себя одинаково для аргументов разных типов (например, функция `add()` — одинаково кладет в контейнер элементы разных типов). +Принцип в ООП, когда программа может использовать объекты с одинаковым интерфейсом без информации о внутреннем устройстве объекта, называется полиморфизмом. + +Пример: + +Давайте представим, что нам в программе нужно описать пользователя, который может пользоваться любыми моделями телефона, чтобы позвонить другому пользователю. Вот как можно это сделать: + +```java +public class User { + private String name; + + public User(String name) { + this.name = name; + } + + public void callAnotherUser(int number, AbstractPhone phone) { +// вот он полиморфизм - использование в коде абстактного типа AbstractPhone phone! + phone.call(number); + } +} +``` + +Теперь опишем различные модели телефонов. Одна из первых моделей телефонов: +```java +public class ThomasEdisonPhone extends AbstractPhone { + + public ThomasEdisonPhone(int year) { + super(year); + } + + @Override + public void call(int outputNumber) { + System.out.println("Вращайте ручку"); + System.out.println("Сообщите номер абонента, сэр"); + } + + @Override + public void ring(int inputNumber) { + System.out.println("Телефон звонит"); + } +} +``` + +Обычный стационарный телефон: + +```java +public class Phone extends AbstractPhone { + + public Phone(int year) { + super(year); + } + + @Override + public void call(int outputNumber) { + System.out.println("Вызываю номер" + outputNumber); + } + + @Override + public void ring(int inputNumber) { + System.out.println("Телефон звонит"); + } +} +``` + +И, наконец, крутой видеотелефон: + +```java +public class VideoPhone extends AbstractPhone { + + public VideoPhone(int year) { + super(year); + } + + @Override + public void call(int outputNumber) { + System.out.println("Подключаю видеоканал для абонента " + outputNumber); + } + + @Override + public void ring(int inputNumber) { + System.out.println("У вас входящий видеовызов..." + inputNumber); + } +} +``` + +Создадим объекты в методе main() и протестируем метод callAnotherUser: + +```java +AbstractPhone firstPhone = new ThomasEdisonPhone(1879); +AbstractPhone phone = new Phone(1984); +AbstractPhone videoPhone=new VideoPhone(2018); +User user = new User("Андрей"); +user.callAnotherUser(224466,firstPhone); +// Вращайте ручку +//Сообщите номер абонента, сэр +user.callAnotherUser(224466,phone); +//Вызываю номер 224466 +user.callAnotherUser(224466,videoPhone); +//Подключаю видеоканал для абонента 224466 +``` + +Используя вызов одного и того же метода объекта user, мы получили различные результаты. Выбор конкретной реализации метода call внутри метода callAnotherUser производился динамически на основании конкретного типа вызывающего его объекта в процессе выполнения программы. В этом и заключается основное преимущество полиморфизма – выбор реализации в процессе выполнения программы. + +В примерах классов телефонов, приведенных выше, мы использовали переопределение методов – прием, при котором изменяется реализация метода, определенная в базовом классе, без изменения сигнатуры метода. По сути это является заменой метода, и именно новый метод, определенный в подклассе, вызывается при выполнении программы. + +Обычно, при переопределении метода, используется аннотация @Override, которая подсказывает компилятору о необходимости проверить сигнатуры переопределяемого и переопределяющего методов. + [к оглавлению](#ООП) ## Что такое _«абстракция»_? @@ -86,6 +273,36 @@ _Абстрагирование_ – это способ выделить наб >Представьте, что водитель едет в автомобиле по оживлённому участку движения. Понятно, что в этот момент он не будет задумываться о химическом составе краски автомобиля, особенностях взаимодействия шестерёнок в коробке передач или влияния формы кузова на скорость (разве что, автомобиль стоит в глухой пробке и водителю абсолютно нечем заняться). Однако, руль, педали, указатель поворота он будет использовать регулярно. +Пример: +```java +// Abstract class +abstract class Animal { + // Abstract method (does not have a body) + public abstract void animalSound(); + + // Regular method + public void sleep() { + System.out.println("Zzz"); + } +} + +// Subclass (inherit from Animal) +class Pig extends Animal { + public void animalSound() { + // The body of animalSound() is provided here + System.out.println("The pig says: wee wee"); + } +} + +class MyMainClass { + public static void main(String[] args) { + Pig myPig = new Pig(); // Create a Pig object + myPig.animalSound(); + myPig.sleep(); + } +} +``` + [к оглавлению](#ООП) ## Что представляет собой _«обмен сообщениями»_?