2016-01-06 20 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不能提供这种基本的机制。 –