2016-01-06 49 views
2

我在C++方面有比Go更多的經驗。我試圖理解如何在Go中慣用地表達Composite design pattern,特別是參考了屬性。在C++中,我將使用父類來保存一組子類通用的屬性和方法。我沒有看到這在Go中如何工作。一個接口允許我定義要實現的方法,但它不允許我提供默認實現。我必須在實現接口的每個結構中重新實現該方法,並複製每個結構中的所有屬性。我無法在接口中保留常用屬性,因爲接口沒有數據元素。你如何在Go中進行這種重構?相當於子類的習語轉到

這裏的(在C++)什麼,我想能在去做一個例子:

#include <string> 

/* 
* Parent class for edible things. Holds the "name" attribute. 
*/ 

class Edible { 
public: 
     Edible(const std::string &aName): 
       ed_Name(aName) { } 
     const std::string &name() const { return ed_Name; } 

protected: 
     void setName(const std::string &aName) { ed_Name = aName; } 

private: 
     std::string ed_Name; 
}; 

/* 
* Subclass of Edible for fruits. Depends on Edible to store the name. 
*/ 

class Fruit: public Edible { 
public: 
     Fruit(const std::string &aName, 
       const std::string &aPlant): 
       Edible(aName), 
       fr_Plant(aPlant) { } 
     const std::string &plant() const { return fr_Plant; } 

protected: 
     void setPlant(const std::string &aPlant) { fr_Plant = aPlant; } 

private: 
     std::string fr_Plant; 
}; 

/* 
* Subclass of Edible for meats. Depends on Edible to store the name. 
* Has attributes for the animal and the cut of meat. 
*/ 

class Meat: public Edible { 
public: 
     Meat(const std::string &aName, 
      const std::string &aAnimal, 
      const std::string &aCut): 
       Edible(aName), 
       me_Animal(aAnimal), 
       me_Cut(aCut) { } 
     const std::string &animal() const { return me_Animal; } 
     const std::string &cut() const { return me_Cut; } 
protected: 
     void setAnimal(const std::string &aAnimal) { me_Animal = aAnimal; } 
     void setCut(const std::string &aCut) { me_Cut = aCut; } 
private: 
     std::string me_Animal; 
     std::string me_Cut; 
}; 
+1

Go沒有繼承,所以type層次通常是你想要避免的東西。 C++/Java設計模式不適合Go中使用的結構類型和組合。 – JimB

+0

在Go中搜索嵌入,並閱讀推薦的設計模式。正如JimB所說,你想重新考慮一下設計,從我來描述它的最簡單的方式是繼承關係是顛倒的。你永遠不會繼承,你只能撰寫/嵌入。除此之外,當你使用父類型實現多態行爲時,比如迭代'[] ParentType'並調用'MethodThatsOverriden()',你需要定義一個接口並使用它。 – evanmcdonnal

回答

1

在這種情況下,你可以有一個Edible接口,並且type Fruit structtype Meat struct每個實施他們。其中的每一個也可以組成,使其包含一個EdibleName,它將提供設置/獲取名稱的方法和存儲空間。

例如

type Edible interface { 
    eat() int // common method 
} 

type EdibleName struct { 
    name string 
} 

// NB getters and setters may not be idiomatic 
func (n *EdibleName) getName() string { 
    return n.name 
} 

func (n *EdibleName) setName(name string) { 
    n.name = name 
} 

type Fruit struct { 
    pips int 
    EdibleName 
} 

func (f *Fruit) eat() int { 
    // ... 
    return 0 
} 

type Meat struct { 
    animal int 
    EdibleName 
} 

func (m *Meat) eat() int { 
    animal int 
    return 0 
} 
+0

這是否允許我,例如,有一個Edibles列表,並檢索每個實例的名稱,而不必擔心它是一個水果還是肉?我認爲將GetName()添加到Edible接口會執行此操作,對嗎? –

+0

如果你想這樣做,是的,你需要添加'GetName()'到可編輯界面。或者也許只是返回一個指向'EditableName'的指針,或者你可能會用到的東西('EdibleItem')。 – abligh

+0

在實際的實現中,我有不止一種方法讓頂級接口訪問屬性的值,所以一個方法肯定是要走的路。非常感謝答案。這正是我所錯過的。我知道Go不能提供這種基本的機制。 –