เมื่อ Rob Pike พูดว่า“ Go เป็นเรื่องเกี่ยวกับการแต่งเพลง” เขาหมายถึงอะไรกันแน่? [ปิด]


12

จากLess มีมากขึ้นแบบทวีคูณ

ถ้า 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 ++ ฉันต้องรับช่วงต่อหรือไม่
Doug T.

2
@DougT: ใช่ฉันได้แก้ไขในตัวอย่างที่แสดงความคิดทั่วไปของ (ส่วนหนึ่งของ) สิ่งที่อนุญาต
Jerry Coffin

2
ฉันคิดว่าสิ่งนี้ไม่ตรงประเด็น: ความแตกต่างไม่ได้เป็นเพียงวากยสัมพันธ์ที่บ่งบอกว่าคุณใช้การฝังเพื่อสร้างอนุกรมวิธานของคุณ ความจริงก็คือว่าการขาดวิธีการ OOP จะช่วยป้องกันไม่ให้คุณสร้างอนุกรมวิธานแบบดั้งเดิมและคุณต้องใช้องค์ประกอบแทน
Denys Séguret

1
@dystroy: เมื่อเทียบกับ Java คุณอาจมีประเด็น เมื่อเทียบกับ C ++ ไม่มาก - เพราะอย่างน้อยในหมู่ผู้ที่มีเงื่อนงำยักษ์ใหญ่เหล่านั้นถูกพบเห็นเมื่อเกือบ 20 ปีที่แล้ว
Jerry Coffin

1
@dystroy: คุณยังไม่เข้าใจ ลำดับชั้นสามระดับใน C ++ ที่ทันสมัยอยู่ติดกับที่ไม่เคยได้ยิน ใน C ++ คุณจะเห็นรายการเหล่านั้นในไลบรารี iostreams และลำดับชั้นข้อยกเว้น - แต่ใกล้กับที่อื่นแล้ว ถ้าไลบรารี iostreams ได้รับการออกแบบในวันนี้ฉันคิดว่ามันปลอดภัยที่จะบอกว่าจะไม่เป็นเช่นนั้น บรรทัดล่าง: ข้อโต้แย้งของคุณแสดงน้อยลงเกี่ยวกับ C ++ มากกว่าเกี่ยวกับวิธีที่คุณไม่คุ้นเคยกับมัน เนื่องจากคุณไม่ได้ใช้งานมาหลายทศวรรษแล้ว สิ่งที่ไม่สมเหตุสมผลคือพยายามพูดถึงวิธีการใช้ C ++ จากประสบการณ์ที่ผ่านมา
Jerry Coffin

8

คำถาม / ปัญหานี้เป็นชนิดของคล้ายกับคนนี้

ในระหว่างการเดินทางคุณไม่มี 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 สิ่งนี้จะไม่เรียกฟังก์ชันเฉพาะ แต่เป็นฟังก์ชัน "superclass"

ดังนั้นหากคุณต้องการอัลกอริทึมที่ต้องการเรียกใช้ฟังก์ชันบางอย่างที่กำหนดไว้ใน * 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
}

นี่ค่อนข้างแตกต่างจากการเอาชนะแบบคลาสสิกของลำดับชั้น

โดยเฉพาะอย่างยิ่งคุณไม่สามารถมีระดับที่สามโดยตรงที่สืบทอดการใช้งานฟังก์ชั่นจากระดับที่สอง

ในทางปฏิบัติคุณจะสิ้นสุดการใช้อินเทอร์เฟซ (orthogonal) เป็นส่วนใหญ่และให้ฟังก์ชันเขียนการเรียกบนการใช้งานที่เตรียมไว้แทนที่จะใช้ "ซูเปอร์คลาส" ของการจัดระเบียบการโทรเหล่านั้น

จากประสบการณ์ของฉันสิ่งนี้นำไปสู่การขาดการปฏิบัติของลำดับชั้นลึกกว่าหนึ่งระดับ

บ่อยครั้งที่ภาษาอื่นคุณมีความสะท้อนเมื่อคุณเห็นว่าแนวคิด A เป็นความเชี่ยวชาญเฉพาะของแนวคิด B เพื่อทบทวนความจริงนี้โดยการสร้างคลาส B และคลาส A เป็นคลาสย่อยของ B แทนการสร้างของคุณ โปรแกรมรอบข้อมูลของคุณคุณใช้เวลาในการจำลองอนุกรมวิธานของวัตถุในรหัสของคุณบนหลักการที่ว่านี่คือความจริง

ใน Go คุณไม่สามารถกำหนดอัลกอริทึมทั่วไปและชำนาญได้ คุณต้องกำหนดอัลกอริทึมทั่วไปและให้แน่ใจว่าเป็นเรื่องทั่วไปและทำงานร่วมกับการใช้อินเทอร์เฟซที่ให้ไว้

ต้องตกใจกับความซับซ้อนที่เพิ่มขึ้นของต้นไม้ลำดับชั้นที่ผู้เขียนทำแฮ็กที่ซับซ้อนเพื่อพยายามหาอัลกอริทึมซึ่งในที่สุดตรรกะก็หมายถึงทุกระดับฉันจะบอกว่าฉันมีความสุขกับตรรกะ Go ที่ง่ายกว่าแม้ว่ามันจะบังคับ ให้คุณคิดแทนการปรับเปลี่ยนแนวคิดของโมเดลแอปพลิเคชันของคุณอีกครั้ง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.