롭 파이크 (Rob Pike)가“가는 구성에 관한 것”이라고 말할 때, 그는 정확히 무엇을 의미합니까? [닫은]


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 ++에서 상속해야 할 때 작성하는 데 도움이되는 기능을 제공합니까?
Doug T.

2
@ DougT. : 예, 허용되는 것의 (일부) 일반적인 아이디어를 보여주는 예제에서 편집했습니다.
Jerry Coffin

2
나는 이것이 요점을 놓치고 있다고 생각합니다. 차이점은 구문을 작성하는 데 포함을 사용한다는 것을 의미하는 구문상의 것이 아닙니다. 사실 OOP 방법 재정의가 없으면 고전적인 분류 체계를 구축 할 수 없으므로 대신 컴포지션을 사용해야합니다.
Denys Séguret

1
@ dystroy : Java와 비교할 때 아마도 요점이 있습니다. C ++과 비교할 때 그리 많지 않습니다. (최소 실마리를 가진 사람들 중에서) 그 거대한 분류법은 20 년 전에 마지막으로 목격 되었기 때문입니다.
Jerry Coffin

1
@dystroy : 당신은 여전히 ​​이해하고 있지 않습니다. 현대 C ++의 3 단계 계층 구조는 다음과 같습니다. C ++에서는 iostreams 라이브러리와 예외 계층 구조에있는 것을 볼 수 있지만 다른 곳에서는 거의 없습니다. iostream 라이브러리가 오늘날 설계되고 있다면 그렇게되지 않는다고 말하는 것이 안전하다고 생각합니다. 결론 : 당신의 논거는 C ++에 대한 터치가 얼마나 낫다는 것보다 덜 나타납니다. 당신이 수십 년 동안 그것을 사용하지 않았다는 것을 감안할 때, 그것은 의미가 있습니다. 이해가되지 않는 것은 날짜가 지정된 경험을 기반으로 C ++이 어떻게 사용되는지 말하는 것입니다.
Jerry Coffin

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를 B의 서브 클래스로 작성하여이 사실을 구체화하는 경우가 종종 있습니다. 데이터를 중심으로 프로그래밍하면 코드에서 객체의 분류 체계를 재생산하는 데 시간이 걸리며 이것이 현실이라는 원칙에 따릅니다.

Go에서는 일반 알고리즘을 정의하고 전문화 할 수 없습니다. 일반 알고리즘을 정의하고 일반 알고리즘을 제공하고 제공된 인터페이스 구현과 작동하는지 확인해야합니다.

코더가 복잡한 해킹을 통해 복잡성이 해킹되어 로직이 최종적으로 모든 레벨을 암시하는 알고리즘을 수용하려고 시도함에 따라 점점 더 복잡 해지는 것에 놀랐습니다. 애플리케이션 모델의 개념을 수정하는 대신 생각해야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.