Коли Роб Пайк каже "Іди про композицію", що саме він має на увазі? [зачинено]


12

Від меншого - це експоненціально більше

Якщо C ++ та Java стосуються ієрархій типів та систематики типів, Go - про склад.

Відповіді:


13

Він означає, що там, де ви б щось використовували на замовлення:

class A : public B {};

у чомусь на кшталт Java або C ++, у програмі Go, яку ви використовуєте (щось еквівалентне):

class A {
    B b;
};

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

struct B {
    int foo() {}
};

struct A { 
    B b;
};

A a;

a.foo();  // not allowed in C++ or Java, but allowed in Go.

Для цього, однак, ви використовуєте синтаксис, який не дозволений у C ++ або Java - ви залишаєте вбудований об'єкт без власного імені, тому це більше схоже на:

struct A {
   B;
};

1
Мені цікаво, я роблю це на C ++ (віддаю перевагу композиції). Чи надаються функції, які допомагають мені складати, коли в Java / C ++ мені доведеться успадковувати?
Дуг Т.

2
@DougT .: Так, я відредагував у прикладі показ загальної ідеї (частини) того, що це дозволяє.
Джеррі Труну

2
Я думаю, що це пропускає суть: відмінність - це не просто синтаксичний, що означає, що ви використовуєте вбудовування для побудови своєї систематики. Справа в тому, що відсутність переосмислення методу OOP заважає будувати класичну таксономію і замість цього потрібно використовувати композицію.
Denys Séguret

1
@dystroy: У порівнянні з Java у вас, певно, є точка. Порівняно з C ++, не так вже й багато - тому що (принаймні серед тих, хто має поняття) ці гігантські таксономії востаннє були помічені близько 20 років тому.
Джеррі Труну

1
@dystroy: Ти все ще не розумієш. Трирівнева ієрархія в сучасному C ++ знаходиться поруч із нечуваною. У C ++ ви побачите ті, що знаходяться в бібліотеці iostreams та ієрархії винятків - але близько ніде більше. Якби бібліотека iostreams розроблялася сьогодні, я думаю, що з впевненістю можна сказати, що так би не було. Підсумок: ваші аргументи показують менше про C ++, ніж про те, як ви з ним не торкаєтесь. Зважаючи на те, що ви не використовували його десятиліттями, це має сенс. Що не має сенсу, це намагатися сказати, як C ++ використовується на основі досвіду.
Джеррі Труну

8

Це питання / проблема схожа на цю .

У Go, у вас насправді немає OOP.

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

type ConnexionMysql struct {
    *sql.DB
}

У цьому зразку ConnexionMysql є різновидом спеціалізації * sql.DB, і ви можете зателефонувати на ConnexionMysql функції, визначені на * sql.DB:

type BaseMysql struct {
    user     string
    password string
    database string
}

func (store *BaseMysql) DB() (ConnexionMysql, error) {
    db, err := sql.Open("mymysql", store.database+"/"+store.user+"/"+store.password)
    return ConnexionMysql{db}, err
}

func (con ConnexionMysql) EtatBraldun(idBraldun uint) (*EtatBraldun, error) {
    row := con.QueryRow("select pv, pvmax, pa, tour, dla, faim from compte where id=?", idBraldun)
    // stuff
    return nil, err
}

// somewhere else:
con, err := ms.bd.DB()
defer con.Close()
// ...
somethings, err = con.EtatBraldun(id)

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

Але

якщо функція, визначена на * sql.DB, викликає інші функції, визначені в * sql.DB, вона не буде викликати функції, визначені в ConnexionMysql, навіть якщо вони існують.

Маючи класичну спадщину, ви часто робите щось подібне:

func (db *sql.DB) doComplexThing() {
   db.doSimpleThing()
   db.doAnotherSimpleThing()
}

func (db *sql.DB) doSimpleThing() {
   // standard implementation, that we expect to override
}

Тобто ви визначаєте doComplexThingв суперкласі як організацію за викликами спеціалізацій.

Але в Go це не називатиметься спеціалізованою функцією, а функцією "суперкласу".

Отже, якщо ви хочете мати алгоритм, який потребує виклику деяких функцій, визначених у * sql.DB, але перероблених на ConnexionMySQL (або інших спеціалізаціях), ви не можете визначити цей алгоритм як функцію * sql.DB, але потрібно визначити його в іншому місці і ця функція буде складати лише виклики до наданої спеціалізації.

Ви можете зробити це так, використовуючи інтерфейси:

type interface SimpleThingDoer {
   doSimpleThing()
   doAnotherSimpleThing()
}

func doComplexThing(db SimpleThingDoer) {
   db.doSimpleThing()
   db.doAnotherSimpleThing()
}

func (db *sql.DB) doSimpleThing() {
   // standard implementation, that we expect to override
}

func (db ConnexionMySQL) doSimpleThing() {
   // other implemenation
}

Це сильно відрізняється від класичного переосмислення ієрархій класів.

Тим більше, ви, очевидно, не можете безпосередньо мати третій рівень, успадковуючи реалізацію функції від другого.

На практиці ви закінчите використовувати здебільшого (ортогональні) інтерфейси, а функція дозволить складати виклики за наданою реалізацією, а не "суперклас" для організації цих викликів.

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

Занадто часто в інших мовах у вас виникає рефлекс, коли ви бачите, що поняття A - це спеціалізація поняття B, щоб перетворити цей факт, створивши клас B і клас A як підклас В. Замість створення вашої Програмуючи ваші дані, ви витрачаєте час на відтворення систематики об'єктів у вашому коді за принципом, що це реальність.

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

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

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