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 шт):
Вы определенно приводите не весь код, но по тому коду, который приведен, я бы ответил "нет" на вопрос о том, правильно ли вы используете интерфейс.
Отвечая коротко, возвращайте структуры конкретного класса, а принимайте на вход интерфейсы.
Для длинного ответа надо разобраться с тем, что такое интерфейс - в общем случае это требование к тому, какие методы должны быть у объекта чтобы его можно было подать на вход в функцию.
Если функция принимает на вход интерфейс, это означает "дай мне на вход какой угодно объект, который реализует интерфейс и я внутри буду вызывать методы этого интерфейса независимо от того, какой на самом деле объект мне передан". Это один из способов реализации полиморфизма.
Разные языки реализуют интерфейсы по-разному:
- 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 нарушает принцип сегрегации интерфейсов (и вероятно принцип единственной ответственности) - он отвечает за манипуляции с путем и какие-то действия с веб-запросами. Выглядит как будто его надо распилить на два интерфейса.