Как сохранить код СУХОЙ на Голанге

EDIT++:

Как не повторить мой код в Go?

type Animal interface {
    Kingdom() string
    Phylum() string
    Family() string
}

type Wolf struct {}
type Tiger struct {}

func (w Wolf) Kingdom() string {return "Animalia"}
func (w Wolf) Phylum() string {return "Chordata"}
func (w Wolf) Family() string {return "Canidae"}

Я реализовал три метода для Wolf типа и мне нужно реализовать все методы для Tiger Тип для реализации интерфейса. Но Kingdom а также Phylum методы одинаковы для обоих типов. Можно ли как-то реализовать только Family метод для Tiger тип:

func (t Tiger) Family() string {return "Felidae"}

а не повторять ли все три метода для каждого типа?

отказ

Пожалуйста, не путайте с простыми строковыми возвратами в методах, в реальном случае мне нужны разные реализации методов, а не только предопределенные значения. Используя этот глупый стиль, я хочу избежать осквернения вашего мозга. Так что пропустить методы совсем не так. Спасибо

3 ответа

Решение

Это классическая композиция:

type Wolf struct {
    Animalia
    Chordata
    Canidae
}
type Tiger struct {
    Animalia
    Chordata
    Felidae
}

type Animalia struct{}

func (Animalia) Kingdom() string { return "Animalia" }

type Chordata struct{}

func (Chordata) Phylum() string { return "Chordata" }

type Canidae struct{}

func (Canidae) Family() string { return "Canidae" }

type Felidae struct{}

func (Felidae) Family() string { return "Felidae" }

func main() {
    w := Wolf{}
    t := Tiger{}
    fmt.Println(w.Kingdom(), w.Phylum(), w.Family())
    fmt.Println(t.Kingdom(), t.Phylum(), t.Family())
}

Детская площадка: https://play.golang.org/p/Jp22N2IuHL.

Это очень похоже на неправильное использование интерфейсов. Интерфейсы не являются заменой для классов; они являются выражением того, что может сделать тип. У вас есть данные. Храните данные в структурах.

type Animal struct {
    kingdom string
    phylum  string
    family  string
}

var wolf = Animal{"Animalia", "Chordata", "Canidae"}
var tiger = wolf
tiger.family = "Felidae"

Так как я заинтересован в этой функции, я прочитал несколько статей по этой теме и объединил ее в несколько ориентиров.

Встраивание

Функция называется "встраивание". И это решает проблему с повторными реализациями методов. Базовый синтаксис:

type Person struct {
    Name string
}

type Speaker struct { // Speaker is an abstract concept it has no name
    *Person // There is a type without field name. It is Anonymous.
}

Упаковка и оформление

Да, ООП не существует, но в любом случае код должен быть СУХИМ. Самый ясный способ думать об этой функции - воспринимать ее как структуру с методами. Таким образом, самый верный способ описать анонимные поля - это шаблон "декоратор" (хорошо известный как Pythonistas).

func (a *Speaker) Introduce(){ // But speaker can introduce itself
    fmt.Println(a.Name) // We have direct access to a wrapped struct attributes.
}

Объединение и переопределение

Также мы можем комбинировать методы, реализованные на структурах.

func (s Speaker) Speak() string {
    return "Blah-blah"
}

type Den struct { // Combine Person and Speaker under Den struct
    Person
    Speaker
}

func (d Den) Speak() string { // Override Speak method only for Dennis 
    return "I'm quit!"
}

func main() {
    den := Den{Person: Person{Name: "Dennis",}}
    mike := Speaker{Person: Person{Name: "Michael",}}

    fmt.Println(den.Introduce())
    fmt.Println(den.Speak())
    fmt.Println(mike.Introduce())
    fmt.Println(mike.Speak())
}

Таким образом, мы можем избежать реализации каждого необходимого метода для каждого типа.

Интерфейсы

То же самое с интерфейсами. Но если объединены несколько интерфейсов, это означает, что нам не нужно объявлять методы, которые уже объявлены в используемых интерфейсах.

Детская площадка

Статья в блоге Дениса Суратны

Документы

Другие вопросы по тегам