Страницы

Поиск по вопросам

вторник, 25 февраля 2020 г.

Зачем нужны интерфейсы в golang?

#ооп #golang


Вопрос может показаться глупым. Я недавно изучаю golang. Естественно читал статьи,
но так и не понял.   Что конкретно я могу сделать с интерфейсами и не могу без них(или
с большими затратами)?
Просто я в коде пока их не применял и хочу разобраться, когда их стоит использовать
    


Ответы

Ответ 1



Интерфейсы в Go -- способ реализации полиморфизма. Приведу стандартный пример с фигурами: package main import ( "math" "fmt" ) // Круг. type Circle struct { x, y, r float64 } // Прямоугольник. type Rectangle struct { x1, y1, x2, y2 float64 } // Интерфейс фигуры, которому удовлетворяют все типы, имеющие соответствующий // метод вычисления площади Area(). type Figure interface { Area() float64 } // Реализация интерфейса Figure для Circle. func (c *Circle) Area() float64 { return math.Pi * c.r * c.r } // Реализация интерфейса Figure для Rectangular. func (r *Rectangle) Area() float64 { return math.Abs(r.x2 - r.x1) * math.Abs(r.y2 - r.y1) } func main() { figures := make([]Figure, 0) // Срез фигур. // Мы можем добавлять в этот срез все, что удовлетворяет интерфейсу // Figure, несмотря на то, что это элементы разных типов: figures = append(figures, &Circle{0, 0, 10}) figures = append(figures, &Rectangle{0, 0, 10, 20}) // И теперь мы можем единообразно обрабатывать эти данные разных типов. for _, figure := range figures { fmt.Printf("Area of %#v = %f\n", figure, figure.Area()) } } Результат: $ go run figures.go Area of &main.Circle{x:0, y:0, r:10} = 314.159265 Area of &main.Rectangle{x1:0, y1:0, x2:10, y2:20} = 200.000000

Ответ 2



В golang интерфейсы довольно забавная штукаБ если смотреть на них с точки зрения ООП языков. По большому счету интерфейс в golang это набор методов без имплементации. Если имплементировать эти методы для любого стракта этот стракт можно использовать как тип интерфейсб иногда это довольно удобно. Например есть функция которая должна собрать информацию о разных типах и сохранить их в базу данных, мне необходимо использовать фреймфорк который собирает все query для транзакции: func AddAllEntities(entityName string, entities []entity, defaults map[string]interface{}) { getHookScriptRes("AddPartOfSale", "salePartName", entities) for _, entity := range entities { q.NewAppend("save"+salePartName, entity.GetSaveParams(defaults)...) break } } Так же у меня есть несколько разных страктов entityOne, entityTwo, entityThree и я хочу исподьзовать их как аргумент в функции которая собирает транзакцию. Для этого я создал интерфейс с методом который вытаскивает из страктов нужные мне поля и в мапе связывает их с колонками в таблице: type saveEntity interface { GetSaveParams(defaults map[string]interface{}) map[string]interface{} } И для каждого из страктов я пишу имплементацию этого метода: func (e1 *entityOne) GetSaveParams(defaults map[string]interface{}) []interface{} { tmpMap := map[string]interface{}{ "one": defaults["one"], "two": defaults["two"], "id": e1.Id, } return tmpMap } func (e2 *entityTwo) GetSaveParams(defaults map[string]interface{}) []interface{} { tmpMap := map[string]interface{}{ "one": defaults["one"], "two": defaults["two"], "name": e2.Name, } return tmpMap } func (e3 *entityThree) GetSaveParams(defaults map[string]interface{}) []interface{} { tmpMap := map[string]interface{}{ "one": defaults["one"], "two": defaults["two"], "name": e3.Price, } return tmpMap } Теперь все мои стракты так же являются типом моего интерфейса: saveEntity Одно из самых очевидных применений интерфейсов.

Комментариев нет:

Отправить комментарий