Для тих, хто почитав і зрозумів, як робити наслідування інтерфейсів, але не зрозумів, навіщо.
Минулого разу, на прикладі звичайної сім'ї Іванових ми розібрали, навіщо потрібні інтерфейси.
Продовжуємо оцифровувати неспокійне сімейство.
У кожної людини є якісь звички, які вона ні від кого не успадкувала або нікому не передала у спадок - її особисті звички. У нас завдання: надати кожному члену сім'ї унікальні звички. Переводимо в площину Java: потрібно реалізувати в класах унікальні методи, які належатимуть тільки цим класам.
Що ж, вперед!
Це Петя:
Та ладно, це не так і складно, головне мислити логічно. Адже всі знають навіщо потрібні інтерфейси. Зараз створимо interface ПривычкиМаші, опишемо там методи хлопатиВіями() і прихлюпувати(), імплементуємо його до Маші і справа в капелюсі. Ну і що, що методи з такою назвою вже реалізовані в інших інтерфейсах, один раз можна.
Дійсно, хто знає які плани у сімейства Іванових, якщо народиться Сергій, який успадкує звички від Папи, Мами, ПраДідуся і ще когось із четвертого коліна, кожен раз створювати інтерфейс, типу: interface ПривычкиСергія, і там оголошувати методи, які вже можуть бути оголошені сотні разів в інших інтерфейсах?
Через пару-трійку поколінь ми ризикуємо отримати інтерфейси з купою однакових методів, які вже описані в інших інтерфейсах, і якщо треба буде змінити найменування якоїсь звички (а це досить реально – адже світ змінюється), то як розібратися в цьому спагетті, я не уявляю.
Залишається тільки сидіти і мріяти про диво.
От якби для кожної звички був свій інтерфейс.
Давайте уявимо:
Намальована людина права, так насправді можна - тепер симуляція сімейства Іванових врятована!
Уважний читач може задати питання: "А навіщо плодити інтерфейси для кожного члена сім'ї? У нас є набір дій - одразу імплементувати потрібному класу."
Уявимо, що в багатьох паралельних світах існують двійники Петі, і всім Петям треба імплементувати interface ПривычкиПеті
class Петя implements ПривычкиПапи, ПривычкиМами {
//це особисті Петіні звички
public void ковырятиВНосі () {
System.out.println("Ковир-ковир");
}
//це успадковані звички
@Override
public void прихлюпувати() {
System.out.println("Хлюп");
}
@Override
public void підтискати () {
System.out.println("Підтиснути губки");
}
}
Це Папа:
class Папа implements ПривычкиПапи {
//це особисті Папині звички
public void чесатиБороду () {
System.out.println("Чухаю бороду");
}
//це передані звички
@Override
public void прихлюпувати() {
System.out.println("Хлюп");
}
}
Це Мама:
class Мама implements ПривычкиМами{
//це особисті Мамини звички
public void хлопатиВіями () {
System.out.println("Хлоп-хлоп");
}
//це передані звички
@Override
public void підтискати() {
System.out.println("Підтиснути губки");
}
}
Ідеально! Все працює як треба!
У першій статті говорилося, що програма — це відображення реального світу. Найцікавіша властивість реальності – це постійно змінюватися. Сім'я Іванових не стала винятком, у них з'явилася лапочка-дочка на ім’я Маша. І вона успадкувала від Мами звичку хлопати віями, а від Папи прихлюпувати. Треба вносити зміни до нашої програми.
Та ладно, це не так і складно, головне мислити логічно. Адже всі знають навіщо потрібні інтерфейси. Зараз створимо interface ПривычкиМаші, опишемо там методи хлопатиВіями() і прихлюпувати(), імплементуємо його до Маші і справа в капелюсі. Ну і що, що методи з такою назвою вже реалізовані в інших інтерфейсах, один раз можна.
Дійсно, хто знає які плани у сімейства Іванових, якщо народиться Сергій, який успадкує звички від Папи, Мами, ПраДідуся і ще когось із четвертого коліна, кожен раз створювати інтерфейс, типу: interface ПривычкиСергія, і там оголошувати методи, які вже можуть бути оголошені сотні разів в інших інтерфейсах?
Через пару-трійку поколінь ми ризикуємо отримати інтерфейси з купою однакових методів, які вже описані в інших інтерфейсах, і якщо треба буде змінити найменування якоїсь звички (а це досить реально – адже світ змінюється), то як розібратися в цьому спагетті, я не уявляю.
Залишається тільки сидіти і мріяти про диво.
От якби для кожної звички був свій інтерфейс.
Давайте уявимо:
public interface ПривычкаПрихлюпувати {
public void прихлюпувати();
}
public interface ПривычкаПідтискати {
public void підтискати();
}
public interface ПривычкаКовырятиВНосі {
public void ковырятиВНосі();
}
public interface ПривычкаХлопатиВіями {
public void хлопатиВіями();
}
public interface ПривычкаЧесатиБороду {
public void чесатиБороду();
}
А потім, можна було б як у лего, за допомогою множинного наслідування з окремих звичок набрати потрібний нам інтерфейс звичок окремого члена сімейства. Якось так:
public interface ПривычкиМами extends ПривычкаПідтискати, ПривычкаХлопатиВіями {
}
public interface ПривычкиПапи extends ПривычкаЧесатиБороду, ПривычкаПрихлюпувати {
}
public interface ПривычкиПеті extends ПривычкаПідтискати, ПривычкаПрихлюпувати,ПривычкаКовырятиВНосі {
}
public interface ПривычкиМаші extends ПривычкаПрихлюпувати, ПривычкаХлопатиВіями {
}
А потім просто імплементувати потрібний інтерфейс потрібному класу, наприклад, Мамі:
class Мама implements ПривычкиМами{
@Override
public void хлопатиВіями () {
System.out.println("Хлоп-хлоп");
}
@Override
public void підтискати() {
System.out.println("Підтиснути губки");
}
}
Так само можна було б вчинити з Папою, Петею і Машею. І потім, при розширенні сімейства Іванових, проблем би із звичками не було, ми просто би їх тасували через наслідування на рівні інтерфейсів, як інгредієнти в салаті, і не плодили купу методів з однаковими назвами. Ех, мрії, мрії…
Намальована людина права, так насправді можна - тепер симуляція сімейства Іванових врятована!
Уважний читач може задати питання: "А навіщо плодити інтерфейси для кожного члена сім'ї? У нас є набір дій - одразу імплементувати потрібному класу."
Уявимо, що в багатьох паралельних світах існують двійники Петі, і всім Петям треба імплементувати interface ПривычкиПеті
interface ПривычкиПеті extends ПривычкаПідтискати, ПривычкаПрихлюпувати,ПривычкаКовырятиВНосі
class ПетяВсесвітХ implements ПривычкиПеті
class ПетяВсесвітY implements ПривычкиПеті
// і т.д.
А якби загального інтерфейсу не було
class ПетяВсесвітХ implements ПривычкаПідтискати, ПривычкаПрихлюпувати,ПривычкаКовырятиВНосі
class ПетяВсесвітY implements ПривычкаПідтискати, ПривычкаПрихлюпувати,ПривычкаКовырятиВНосі
// і т.д.
Виходить більш об'ємний повторюваний код.
Наслідування інтерфейсів робить застосунок більш гнучким до змін, зокрема — можна вирішити проблеми з повторюваними методами.
Ще раз зверніть увагу, що множинне наслідування інтерфейсів — дозволено.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ