Golang interface. Правильно ли я их использую?

не так давно я начал изучать язык Go, и есть некоторые проблемы с понимание interface. А конкретно их использование.

В данном примере я пытаюсь реализовать маленький обработчик путей (не суть)

Допустим у меня есть такой интерфейс и структура

type F struct {}

type IPath interface {
    Path(path string) IFastUniversal
    ServeHTTP(w http.ResponseWriter, r *http.Request)
}

его реализация:

    /*encapsulate method / create Fast*/
func (f *F) create() IPath {

    /*logic method*/
    println("working with create")

    return f
}

func (f *F) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, "work")
}

/*func create encapsulate method*/
func createHandler(f IFast) IPath {
    return f.create()
}

/*func create Fast handler*/
func Create() IPath {
    return createHandler(&F{})
}

Почему я могу игнорировать интерфейс и добавлять к нему дополнительные методы и интерфейс не будет вызывать ошибок.

пример:

func (f *F) NewCoolMethod() {
    println("Yes i'm cool method!")
}

почему эта строка не вызывает ошибку?

    /*func create Fast handler*/
func Create() IPath {
    return createHandler(&F{})
}

Ведь в интерфейсе отсутствует новый метод.

И если это нормально, правильно ли я его использую в данном случае? Не легче ли просто вернуть саму структуру? Прошу прощения за такой простой вопрос,но я немного в замешательстве.

    func (f *F) Path(path string) IFastUniversal {

    formatingPath := Utils.CreatePath(path)

    route[formatingPath] = RouteData{}

    return f
}

Ответы (1 шт):

Автор решения: Bearded Beaver

Вы определенно приводите не весь код, но по тому коду, который приведен, я бы ответил "нет" на вопрос о том, правильно ли вы используете интерфейс.

Отвечая коротко, возвращайте структуры конкретного класса, а принимайте на вход интерфейсы.

Для длинного ответа надо разобраться с тем, что такое интерфейс - в общем случае это требование к тому, какие методы должны быть у объекта чтобы его можно было подать на вход в функцию.

Если функция принимает на вход интерфейс, это означает "дай мне на вход какой угодно объект, который реализует интерфейс и я внутри буду вызывать методы этого интерфейса независимо от того, какой на самом деле объект мне передан". Это один из способов реализации полиморфизма.

Разные языки реализуют интерфейсы по-разному:

  • C++ (и емнип Java и C#) требуют чтобы объект наследовал интерфейс и реализовывал его методы
  • Python не указывает интерфейс при объявлении функции, но если передать ему объект с несовместимым интерфейсом, сломается при попытке вызвать внутри функции метод интерфейса, не существующий у данного объекта
  • Go в свою очередь указывает, что в функцию передается объект, реализующий интерфейс, как в C++/C#/Java, но не требует никакого указания что конкретная структура реализует интерфейс. Компилятор определит что структура реализует соответствующий интерфейс если структура реализует все методы интерфейса.

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

Возвращаясь к вашему коду, насколько я вижу, структура F не реализует интерфейс IPath (кстати в Go не принято именовать интерфейсы с префиксом I), так как в списке ее методов нет методов интерфейса -

Path(path string) IFastUniversal
ServeHTTP(w http.ResponseWriter, r *http.Request)

В коде интерфейс вы будете использовать в функции, которая работает с объектами, реализующими интерфейс. А при создании объектов, реализующих интерфейс, рекомендуется возвращать конкретные структуры.

З.Ы. Если говорить в терминах SOLID, то ваш интерфейс IPath нарушает принцип сегрегации интерфейсов (и вероятно принцип единственной ответственности) - он отвечает за манипуляции с путем и какие-то действия с веб-запросами. Выглядит как будто его надо распилить на два интерфейса.

→ Ссылка