Як я можу пояснити корисність спадкування? [зачинено]


16

Намагаючись пояснити поняття спадкування в ООП, загальним прикладом часто є приклад ссавців. ІМХО, це насправді поганий приклад, оскільки він призведе новачків до використання цієї концепції неправильним шляхом. І більше того, це не звичайний дизайн, з яким вони зіткнуться у своїй щоденній роботі по дизайну.

Отже, що буде приємною, простою та конкретною проблемою, яку вирішують за допомогою спадкування?


1
"загальним прикладом часто є ссавці"? Що ви маєте на увазі? Чи можете ви надати посилання, посилання або цитату для цього?
S.Lott


3
Що було б найкращим реальним прикладом для пояснення корисності спадщини = дитячого цільового фонду Білла Гейтса?
Мартін Бекетт

1
@Chris: як це питання не конструктивне? Ви заявляєте, що один запитувач і 14 відповідачів витрачають час на всіх?
Дан Даскалеску

@DanDascalescu - його було закрито два роки тому у відповідь на прапор, в якому сказано, "будь ласка, вважайте, що закриття не є конструктивним: якщо судити по написаних на ньому відповідях, це виглядає як типовий список / опитування". Якщо ви вважаєте, що це неправильно, відредагуйте його, щоб дати зрозуміти, що це не так, і дозвольте спільноті вирішувати через чергу повторного огляду.
ChrisF

Відповіді:


15

З чисто академічним прикладом, як ссавці, немає нічого поганого. Мені також подобається приклад прямокутника / квадрата, тому що він вказує, чому таксономії реального світу не завжди прямо переводяться на спадкові відносини, які ви очікували.

На мою думку, найбільш канонічним прикладом кожного дня є інструментарій GUI. Це щось, чим користувалися всі, але, можливо, початківці не міркували, як вони працюють під кришкою. Ви можете говорити про те, що поведінка є загальною для всіх контейнерів, усіх віджетів, подій тощо, не вимагаючи детальних знань про будь-яку реалізацію.


5
+1 для наборів інструментів GUI ... і мені також подобається приклад фігур, з однією формою як базовою з мінімальним малюнком () та нащадками з набором малюнків () s.
yati sagade

14

Мій реальний приклад - доменна модель простого HR-додатку. Я кажу, що ми можемо створити базовий клас під назвою Співробітник , тому що, звичайно, менеджери теж працівники.

public class Employee
{
    public string FirstName { get; set; }

    public string LastName { get; set; }

    public int Code { get; set; }

    public string GetInsuranceHistory()
    {
        // Retrieving insurance history based on employee code.
    }
}

Потім я пояснюю, що розробники - це працівники , тестери - працівники , керівники проектів - службовці . Таким чином, всі вони можуть успадкувати від працівника клас.


2
Щоб показати переваги успадкування, може бути цікавим також показати, чим розробники відрізняються від співробітників. Якщо різниці немає, то взагалі не потрібно створювати клас розробника.
Девід

3
Здається, Employeeце abstractтеж може бути класом.
StuperUser

+1 це приклад, який використовували більшість моїх викладачів, і мені це дуже сподобалось. це мало повний сенс і дало реальний приклад світу щодо використання спадщини.
Девід Пітерман

18
За винятком того, що це ніколи не працює на практиці, оскільки завжди є принаймні одна людина, якій потрібно бути Developerі a Tester. Інша подібна ситуація - це база даних контактів, де ви є , але, як скаже вам кожен, хто створив таку систему, завжди є випадок, коли a є Customerі тим Supplier, і іншим Company. Ось чому більшість із цих прикладів ведуть вас у неправильному напрямку.
Скотт Вітлок

11

Інкапсулюйте те, що варіюється ... покажіть їм шаблон шаблону методу , він демонструє корисність успадкування шляхом розміщення загальної поведінки в базовий клас та інкапсуляції різної поведінки в підкласах.

UI controlsа Streamsтакож є дуже хорошим прикладом корисності спадкування.


Я думаю, що фабрика була б кращим прикладом.
Let_Me_Be

1
@Let_Me_Be: Я вважаю, що відносини між фабрикою та спадщиною є надто непрямими за своєю суттю. Звичайно, він створює конкретні типи та повертає абстрактні / базові типи, але він також може повернути лише тип інтерфейсу! Імхо, це не краще, ніж класичний приклад для тварин.
Сокіл

@Let_Me_Be: Також абстрактна фабрика є досить складним прикладом, що включає різні ієрархії успадкування (одна для предметів, друга для заводів). Я думаю, що це вдале використання спадщини, але не хороший і простий приклад.
Сокіл

3

Пам'ятайте

Кожен екземпляр предмета - конкретний приклад корисності спадкування!

Якщо ви маєте на увазі конкретно класичне успадкування, то зараз ви знаходитесь у світі систематики, і вони різко відрізнятимуться від цілей системи, яка їх використовує. Приклад тварин / ссавців використовує загальну та сподіваюсь звичну систематику з біології, але це (як ви вже згадували) майже марно для переважної більшості проблем програмування.

Тому спробуйте щось універсальне: поняття програми. Кожна програма починається, працює і закінчується. Кожна програма має назву та необов'язкові параметри командного рядка. Тож базовий клас програми був би дуже корисним для початку виконання, захоплення та обробки аргументів командного рядка, запуску основної логіки та граціозно вимкнення.

Ось чому так багато об'єктно-орієнтованих мов програмування забезпечують клас програми, або щось таке, що поводиться точно як клас програми.


Отже, ви програмуєте програму, у якій багато програм? :) На мій досвід, об'єкти програми майже завжди є одинаковими, які не мають спадку, тому вони не є найкращим прикладом.
кеппла

@keppla: ти коли-небудь використовував Java або .NET? .NET має явний програмний клас, Java явний. Вони не одинаки
Стівен А. Лоу

Я використовував Java, навколо версії 1.4.2. Тоді там була лише статична порожнеча основної, тому я здогадуюсь, що вона трохи змінилася. Що може бути типовою причиною наявності декількох екземплярів класу Programm?
кеппла

@keppla: статичний параметр java main явно змушує клас вступу представляти програму. Кожен користувач, який запускає вашу програму, створює її новий примірник. На даний момент у мене працює три екземпляри Google Chrome, чотири документи Word, три блокноти та два Windows Explorer. Якби вони були одинаками, я ніколи цього не зміг би зробити.
Стівен А. Лоу

1
я думаю, ви трохи розтягуєте визначення. class Programm { public static void main(String[] args) { system.out.println('hello world'); }}- мінімальна програма Java. Коли я називаю це, жодного примірника програми. Програма не наслідує ні від чого. Коли я запускаю 3 Процеси (як ви робите з crhome), можливо, є три Програми, але в їх окремих областях пам’яті ще є лише одна Програма. Імхо, синглтон означає "лише один екземпляр на процес", а не на машину. Якщо так, неможливо зробити одиночні кнопки, ніщо не заважає виконувати будь-який код двічі.
кеппла

3

Я працюю з камерами на роботі. У нас є пристрої, які підключаються до різних моделей, тому у нас є абстрактний "клас камери", і кожна модель успадковується від цього класу для підтримки певної функціональності цієї камери. Це справжній світовий приклад і його не важко зрозуміти.


2
Це може вийти з ладу, якщо у вас є, наприклад, модель, яка є і a, Cameraі a Phone(як ми всі зараз робимо в наших кишенях). Від якого базового класу він має успадкувати? Або не слід просто реалізовувати ICameraі IPhoneінтерфейси, і інтерфейси? (ха-ха)
Скотт Вітлок

2
@Scott: Ви не можете реалізувати інтерфейс IPhone, інакше Apple позоветься до вас.
Мейсон Уілер

3

Приклад хімічних елементів

Це ще один приклад, що вискочив з мого мозку:

клас Елемент_
{
    подвійний атомний вагу; // Атомна маса елемента
    подвійне атомне число; // Атомне число елемента
    Властивості рядків; // Властивості елемента
    // Інші, якщо такі є
}


клас Isotope extends Element_ // Там можуть існувати ізотопи елемента
{
    подвійний напівжиття;
   // Інші, якщо такі є

}

2
Хоча atomicNumber може (повинен?), Ймовірно, бути цілим ...
Андрій

Я б не використовував для цього спадщину. isotopeне є особливим випадком Elemenet. Я вважаю за краще мати Elementнерухомість Isotope.
CodesInChaos

2

Реальні приклади майже завжди отримують це неправильно , тому що вони дають приклади , де завжди є можливість що - то бути одночасно TypeAі , TypeBале єдина ієрархія наслідування багатьох мов не дозволяє цього.

Чим більше я програмую, тим більше я відволікаюсь від спадщини.

Тут навіть неправильно вживається слово "успадкувати". Наприклад, ти успадковуєш близько 50% рис батька і 50% рис матері. Дійсно ваша ДНК - це складова половини ДНК вашого батька і половини ДНК вашої матері. Це тому, що біологія насправді надає перевагу складу над спадщиною , і вам слід.

Просто реалізація інтерфейсів, а ще краще, "тик качок", а також ін'єкція залежностей, є набагато кращою справою навчати людей, які не знайомі з об'єктно-орієнтованим програмуванням.


1

Я б просто показав їм приклад із реального життя. Наприклад, у більшості фреймворків інтерфейсу ви походить із якогось класу "Діалог" чи "Вікно" чи "Керування", щоб зробити свій власний.


1

Хорошим прикладом є функція порівняння при сортуванні:

template<class T>
class CompareInterface {
public:
   virtual bool Compare(T t1, T t2) const=0;
};
class FloatCompare : public CompareInterface<float> { };
class CompareImplementation : public FloatCompare {
public:
   bool Compare(float t1, float t2) const { return t1<t2; }
};
template<class T>
void Sort(T*array, int size, CompareInterface<T> &compare);

Єдина проблема - новачки занадто часто думають, що продуктивність важливіша, ніж хороший код ...


0

Мій реальний приклад світу - транспортний засіб:

public class Vehicle
{
    public Vehicle(int doors, int wheels)
    {
        // I describe things that should be
        // established and "unchangeable" 
        // when the class is first "made"
        NumberOfDoors = doors;
        NumberOfWheels = wheels;
    }

    public void RollWindowsUp()
    {
        WindowsUp = true;
    }

    // I cover modifiers on properties to show
    // how to protect certain things from being
    // overridden
    public int NumberOfDoors { get; private set; }
    public int NumberOfWheels { get; private set; }

    public string Color { get; set; }
    public bool WindowsUp { get; set; }
    public int Speed { get; set; }
}

public class Car : Vehicle
{
    public Car : base(4, 4)
    {

    }
}

public class SemiTruck : Vehicle
{
    public SemiTruck : base(2, 18)
    {

    }
}

Цей приклад може бути настільки детальним, наскільки ви хочете, і до транспортних засобів додаються всі види властивостей, які пояснюють використання будь-яких модифікаторів, які ви хочете навчити.


2
Я завжди ненавидів використання транспортних засобів як приклад, оскільки це не дає новому програмісту ближче до розуміння того, як успадкування може використовуватися для поліпшення коду. Транспортні засоби - це надзвичайно складні машини, які закликають до уваги безліч абстрактних ідей у ​​свідомості непрограміста. Намагання описати це в коді змушує пересічного новачка вважати, що багато деталей залишається поза прикладом і створює відчуття, що вони не ближче до того, щоб щось працювати. Я говорю це з досвіду, тому що саме так я відчував себе, коли хтось намагався використовувати транспортні засоби, щоб пояснити це мені.
riwalk

@ Stargazer712: Я використовую транспортні засоби насамперед тому, що вони можуть бути такими ж складними або простими, як вам подобається. Я залишаю це за рішенням інструктора, щоб визначити рівень його учня. Я пояснив базовий OOP дружині (яка має нульовий досвід програмування), використовуючи прості властивості транспортного засобу, що описують загальні основи. У всіх транспортних засобах є двері, у всіх транспортних засобів є колеса тощо. Приклад об'єкта не можна звинувачувати в поганому плані уроків.
Джоель Етертон

ваша дружина не намагалася написати код. Я дуже сміливо можу сказати, що приклади транспортних засобів нічого не допомогли мені зрозуміти спадщину. Що б ви не використовували для опису спадщини, воно повинно бути повним і практичним . Мета - не описати це таким чином, щоб непрограміст міг це зрозуміти. Мета полягає в тому, щоб описати його таким чином , щоб програміст може використовувати його, і єдиний спосіб зробити це , щоб показати приклади того , як початківці професійний програміст буде використовувати його.
riwalk

@ Stargazer712: Я б поставив вашу нездатність спочатку зрозуміти спадщину на поганому плані уроків. Я також використовував транспортні засоби, щоб пояснити спадщину юніорам, з якими працюю, і у мене ніколи не було проблем з траплянням цієї концепції. На мою думку, якщо план уроку є ретельним та належним чином побудованим, об’єкт транспортного засобу є і повним, і практичним. 1 випадковий хлопець в Інтернеті не збирається змінити це перед обличчям 30-ти стажистів та молодших розробок, яким я навчав ООП. Якщо вам не подобається транспортний засіб, голосуйте та рухайтесь далі.
Джоел Етертон

Як хочеш ....
riwalk

0

Цей приклад не ссавців, не птахів, не риб може допомогти:

public abstract class Person {

    /* this contains thing all persons have, like name, gender, home addr, etc. */

    public Object getHomeAddr() { ... }

    public Person getName() { ... }

}

public class Employee extends Person{

    /* It adds things like date of contract, salary, position, etc */

    public Object getAccount() { ... }

}

public abstract class Patient extends Person {
    /* It adds things like medical history, etc */
}

Потім

public static void main(String[] args) {

    /* you can send Xmas cards to patients and employees home addresses */

    List<Person> employeesAndPatients = Factory.getListOfEmployeesAndPatients();

    for (Person p: employeesAndPatients){
        sendXmasCard(p.getName(),p.getHomeAddr());
    }

    /* or you can proccess payment to employees */

    List<Employee> employees = Factory.getListOfEmployees();

    for (Employee e: employees){
        proccessPayment(e.getName(),e.getAccount());
    }       

}

ПРИМІТКА: Просто не кажіть секрет: особа поширює ссавця.


1
Працює, поки хтось із ваших співробітників теж не є пацієнтом.
Скотт Вітлок

У цьому випадку я думаю, що має сенс оголосити пацієнта та працівника інтерфейсами замість абстрактних класів. Це дає вам гнучкість дозволити особі реалізувати декілька інтерфейсів.
Джин Кім

@JinKim - Я повністю згоден, це кращий підхід.
Скотт Уїтлок

@JinKim Вони не є ексклюзивними. Ви ставитесь до людини як до працівника або як до пацієнта в будь-який момент часу, але не в той самий час. Два інтерфейси добре, але тоді, коли ви називаєте конкретний клас, що реалізує обидва, EmployeePatient? Скільки комбінацій у вас буде?
Tulains Córdova

Ви можете назвати конкретний клас все, що завгодно. Якщо код розраховує лише на співробітників, ви декларуєте посилання як працівника. (тобто працівник працівника = нова особа ();) Якщо код очікує стосунків лише з пацієнтом, ви оголошуєте посилання як пацієнта. Рідко ви хочете оголосити посилання безпосередньо як конкретний клас.
Джин Кім

0

Як щодо ієрархії алгебраїчних виразів. Це добре, оскільки включає в себе спадщину та склад:

+--------------------+------------------------+
| Expression         |<------------------+    |
+--------------------+----------+        |    |
| + evaluate(): int  |<---+     |        |    |
+--------------------+    |     |        |    |
          ^               |     |        |    |
          |               |     |        |    |
   +--------------+  +---------------+  +-------------+  ...
   | Constant     |  | Negation      |  | Addition    |
   +--------------+  +---------------+  +-------------+
   | -value: int  |  |               |  |             |
   +--------------+  +---------------+  +-------------+
   | +evaluate()  |  | +evaluate()   |  | +evaluate() |
   | +toString()  |  | +toString()   |  | +toString() |
   +--------------+  +---------------+  +-------------+

   Addition(Constant(5), Negation(Addition(Constant(3),Constant(2))))
   (5 + -(3 + 2)) = 0

За винятком кореневого виразу Constant, всі інші вирази є одночасно виразом і містять один або кілька виразів.


-1

Я буду використовувати для прикладу птахів

як курка, качка, орел

Я поясню, що обидва мають кігті, клювання та крила, але їхні атрибути різні.

Кури не вміють літати, не вміють плавати, можуть їсти глистів, можуть їсти зерна

Качки не вміють літати, вміють плавати, їсти зерно, не можуть їсти глистів

Орел може літати, не вміє плавати, їсти глистів, не може їсти зерна


4
Я колись читав, що композиція та інтерфейси - це, мабуть, найкращий спосіб передати цей тип концепції, тобто літати, плавати тощо.
dreza

Качка не може літати ?!
Адам Кемерон

-3

Ваш типовий рейки-клон пропонує безліч практичних прикладів : у вас є (абстрактний) базовий клас моделі, який інкапсулює всі маніпулювання даними, і у вас базовий клас контролера, який інкапсулює всю HTTP-комунікацію.


Хочете розібратися, чому ця відповідь погана?
кеппла
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.