Comments 17
Sorry, а есть где-то примеры для понимания интерфейсов, например, для логики бэкэнда типового сайта продаж или учетной системы (купил/продал/кому/дата… номенклатура), чтобы увидеть, как они помогают. Люблю животных, но лично мне на их примере не заходит. Возможно, Вам будет удобно привести пример. Я понимаю, что интерфейсы пользуют во всю (web серверы ..), но вот простых примеров, как было бы без них и с ними, — не встречал. Спасибо.
0
Согласен на 100%, вообще ничего не понятно, что автор хотел сказать. Если хоть он сам понял, и то хорошо.
P.S. Не говорю, что я написал бы лучше.
P.S. Не говорю, что я написал бы лучше.
0
Чтобы понять статью, стоит для начала прочитать оригинал указанный во введении.
Если же вы его прочли и не поняли развитие идеи, попробую все таки пояснить.
Если же вы его прочли и не поняли развитие идеи, попробую все таки пояснить.
- В оригинальной статье есть раздел «Do This Instead». Здесь в разделе «Поиграем с абстракциями», я пытаюсь показать, что не всегда использование таких обобщенных интерфейсов как `Speaker` дает нужный результат.
- Раздел «Расширим поведение» показывает пример того, как на основе интерфейса можно создать абстрактный тип данных. Он соотносится с разделом «Abstract Data Types» из оригинальной статьи. В которой в качестве абстрактного типа дан пример из стандартной библиотеки.
- Разделом «Обсудим размеры интерфейсов» я пытаюсь показать, что «broad interfaces» не всегда являются злом, и не нужно всегда использовать «минимально доступные интерфейсы». Иногде уместнее передать абстрактный тип данных (Animal вместо Speaker).
- Ну и раздел «Теперь немного про Закон Постеля» соотносится с одноименным разделом из оригинальной статьи. Он говорит о том, что не стоит возводить правило «Accept interfaces, return structs» в абсолют.
-1
К сожалению сложно найти OpenSorce «типовой сайт продаж или учетную систему», да еще и на Go.
Могу напимер порекомендовать взглянуть на код платформы для разработки микросервисов go-micro.
Она построена на базе нескольких абстрактных типов, таких как (Codec, Broker, Registry, Selector, Transport...). В исходном коде платформы существуют одноименные интерфейсы и реализуя их вы можете подменять те или иные компоненты системы.
К примеру интерфейс Broker описывает абстрактный брокер сообщений. Реализуя его вы можете использовать любой брокер в вашем приложении. Примеры реализации брокеров для данной платформы можно найти в репозитории micro/go-plugins
Могу напимер порекомендовать взглянуть на код платформы для разработки микросервисов go-micro.
Она построена на базе нескольких абстрактных типов, таких как (Codec, Broker, Registry, Selector, Transport...). В исходном коде платформы существуют одноименные интерфейсы и реализуя их вы можете подменять те или иные компоненты системы.
К примеру интерфейс Broker описывает абстрактный брокер сообщений. Реализуя его вы можете использовать любой брокер в вашем приложении. Примеры реализации брокеров для данной платформы можно найти в репозитории micro/go-plugins
0
Я, возможно, чего-то не понимаю. Но в ваших примерах вы дрессируете дрессировщика.
Классу дрессировщик не нужно знать особенности реализации выполнения команд классами животных.
Может имело смысл ввести интерфейс типа TrainedAnimal, с одним публичным методом ExecuteCommand и уже в нём для каждого класса решать, что собака по команде «Голос» лает, слон — трубит, кошка — выполняет рандомное действие, а человек этот интерфейс вообще не реализует, ибо не дрессированный.
А о том чтоб не попасть на арену цирка в качестве питомца заботиться должен был класс дрессировщика, например, не выставляя публично свой метод Speak. «Если оно говорит по команде, почему мы не можем показывать его на сцене?»
И тогда весь смысл нагромождения интерфейсов из примера теряется. Если оно говорящее — пусть говорит, если дрессированное — пусть выполняет команды. Дрессировщик работает только с дрессированным, а похвалить может любое говорящее, человеков тоже хвалить можно, вроде.
Классу дрессировщик не нужно знать особенности реализации выполнения команд классами животных.
Может имело смысл ввести интерфейс типа TrainedAnimal, с одним публичным методом ExecuteCommand и уже в нём для каждого класса решать, что собака по команде «Голос» лает, слон — трубит, кошка — выполняет рандомное действие, а человек этот интерфейс вообще не реализует, ибо не дрессированный.
А о том чтоб не попасть на арену цирка в качестве питомца заботиться должен был класс дрессировщика, например, не выставляя публично свой метод Speak. «Если оно говорит по команде, почему мы не можем показывать его на сцене?»
И тогда весь смысл нагромождения интерфейсов из примера теряется. Если оно говорящее — пусть говорит, если дрессированное — пусть выполняет команды. Дрессировщик работает только с дрессированным, а похвалить может любое говорящее, человеков тоже хвалить можно, вроде.
+3
Классу дрессировщик не нужно знать особенности реализации выполнения команд классами животных...
Жаль, что вы не привели кода, так бы было чуть проще понять. Но в целом идею я уловил. Если я вас правильно понял, вас смущает метод Tamer.Command(...). И вы предлагаете перенести алгоритм из него внутрь TaimedAnimal.ExecuteCommand(...).
Смотрите, на самом деле дресссировщик не знает особенности того как команда выполняется животным. Данный метод описывает алгоритм который должен произвести дрессировщик по отношению к животному, чтобы оно выполнило команду. Попробую пояснить в виде кода.
func (t *Tamer) Command(action int, a Animal) string {
switch action {
case ActSit:
// Подойти к питомцу
// Стать к нему лицом и наклонится
// Показать питомцу лакомство
return a.Sit() // Произнести команду сидеть
}
return ""
}
Особенности реализации команды животным инкапсулированы внутри этого самого животного.
func (d Dog) Sit() string {
// Посмотреть на дрессировщика
// Выпрямить передние лапы
// Согнуть задние лапы
// Повилять хвостом
return "sit"
}
Надеюсь более менее понятно объяснил?
0
Я не совсем о том. На уровне тех же ваших абстракций, действие («сидеть») выполняется животным и над животным и участие дрессировщика в процессе нужно только для того чтоб отдать команду.
Ваш вариант вполне имеет право на жизнь, но при изменении количества доступных команд/животных, вы столкнётесь с трудностями.
Представьте, например, что появилась у вас обезьяна в цирке, которая знает команду 'читай газету'. В текущем варианте реализации каждому животному нужно будет добавить пустой метод ReadNewspaper. А если бы мы делали через TrainedAnimal, правки нужны были бы только у дрессированной обезьяны, у остальных default case для всех невыполнимых команд.
Сделать так чтоб по команде «сидеть», обезьяна не тупо садилась, а приносила стул (monkey.BringChair) и начинала читать газету (monkey.ReadNewspaper) в принципе невозможно получается (метод Sit у обезьяны есть, но тут нам не нужен).
Как минимум, он знает что команда выполняется только тренированным животным, и проверяет тренированность при каждом вызове команды, эта проверка как раз могла бы быть проведена во время проверки интерфейса и один раз.
Ваш вариант вполне имеет право на жизнь, но при изменении количества доступных команд/животных, вы столкнётесь с трудностями.
Представьте, например, что появилась у вас обезьяна в цирке, которая знает команду 'читай газету'. В текущем варианте реализации каждому животному нужно будет добавить пустой метод ReadNewspaper. А если бы мы делали через TrainedAnimal, правки нужны были бы только у дрессированной обезьяны, у остальных default case для всех невыполнимых команд.
Сделать так чтоб по команде «сидеть», обезьяна не тупо садилась, а приносила стул (monkey.BringChair) и начинала читать газету (monkey.ReadNewspaper) в принципе невозможно получается (метод Sit у обезьяны есть, но тут нам не нужен).
Смотрите, на самом деле дресссировщик не знает особенности того как команда выполняется животным.
Как минимум, он знает что команда выполняется только тренированным животным, и проверяет тренированность при каждом вызове команды, эта проверка как раз могла бы быть проведена во время проверки интерфейса и один раз.
+1
Я понимаю, да, можно сделать и так. Здесь возникают trade-off.
А если завтра укротитель захочет все таки «тренировать» не тренированное животное? С абстракцией TamedAnimal, у нас не будет такой возможности получается?
эта проверка как раз могла бы быть проведена во время проверки интерфейса и один раз.
А если завтра укротитель захочет все таки «тренировать» не тренированное животное? С абстракцией TamedAnimal, у нас не будет такой возможности получается?
func (t *Tamer) Command(action int, a Animal) string {
if !a.IsTrained() {
t.train(a, action)
}
...
}
0
Хм, ну мы сможем создавать декоратор, принимающий не тренированное животное и отдающий тренированное. И управлять «тренированностью» для каждого класса. А не внезапно начать тренировать всех.
0
Да, я понимаю, просто все это не совсем имеет отношение к сути статьи. Смотрите, я сделаю так, как вы предлагаете.
Теперь мы имеем более конкретный абстрактный тип. Я согласен. Тем не менее, это не меняет сути статьи. Суть то в том, чтобы показать, как можно создавать абстрактные типы данных используя интерфейсы Go, а так же показать, что использование слишком общих абстракций не всегда дает нужный/ожидаемый результат.
type TamedAnimal interface {
Speaker
Do(command int) string
}
type Tamer struct{}
func (t *Tamer) Speaks() string { return "WAT?" }
func (t *Tamer) Command(action int, a TamedAnimal) string {
return a.Do(action)
}
func (t *Tamer) Praise(a Speaker) string {
return a.Speaks()
}
Теперь мы имеем более конкретный абстрактный тип. Я согласен. Тем не менее, это не меняет сути статьи. Суть то в том, чтобы показать, как можно создавать абстрактные типы данных используя интерфейсы Go, а так же показать, что использование слишком общих абстракций не всегда дает нужный/ожидаемый результат.
0
простите, и вот это предлагается взамен Си и Си++?
:=, *, &? даже начинать учить страшно.
:=, *, &? даже начинать учить страшно.
-2
Go предлагается взамен пыхыпы, шарпа и иже с ними, вроде. Он не позиционируется как язык системного программирования. Взамен Си — Rust, но там вам тоже может страшным показаться.
0
Понял, думал все таки взамен «сложных» С, С++. Взамен PHP и так все это дело усложнить? Какой смысл? Что он дает против PHP? Скорость разработки? Легкость разработки? Судя по этой статье я думаю что вряд ли. Да нет, он мне не кажется страшным :) я так, для красного словца уж использовал что страшно. Начал, но пока только начал учить. Про Rust спасибо, тоже что-то такое слышал, тоже было интересно про него узнать.
0
Против PHP какую-никакую компилируемость, работу с потоками и т.п. По заверениям разработчиков Go даёт что-то типа «врождённой грамотности», т.е. на нём сложнее написать «плохой» код, но не вникал особо глубоко.
Про Rust ничего лучше их «книжки», вроде, и нет doc.rust-lang.org/stable/book/title-page.html
Рекламятся они, в основном, своей механикой выделения/освобождения памяти + возможностью использовать «бесплатно» абстракции высокого уровня, но там много других плюсов и минусов.
Про Rust ничего лучше их «книжки», вроде, и нет doc.rust-lang.org/stable/book/title-page.html
Рекламятся они, в основном, своей механикой выделения/освобождения памяти + возможностью использовать «бесплатно» абстракции высокого уровня, но там много других плюсов и минусов.
0
По работе возникла необходимость выучить Го. Основы легко запоминаются за неделю-две. Синтаксис после С и С++ немного непривычный, но в целом отторжения не вызывает, особенно после фич 11-17го стандарта, некоторые из которых в Го есть как часть языка — например, запись типа возвращаемого значения после аргументов функции (как в многих других языках) или возврат нескольких значений из функции и т.д. Единственный сложный момент — переключение мозга с ООП на использование Гошных интерфейсов. Это примерно как переход с С на С++, может даже немного проще.
Имхо, на текущий момент область использования языка ограничена микросервисами/вебом, т.к. нормальных библиотек/врапперов работы с системными вещами пока нет. Не смотря на обилие гитхабовских репозиториев с врапперами половина из них тухлые/нерабочие (я про системные вещи, типа хоткеев, звука, работы с буфером обмена). Но для тех же микросервисов он хорош и гораздо проще С++ в использовании и освоении (в полном объёме).
Имхо, на текущий момент область использования языка ограничена микросервисами/вебом, т.к. нормальных библиотек/врапперов работы с системными вещами пока нет. Не смотря на обилие гитхабовских репозиториев с врапперами половина из них тухлые/нерабочие (я про системные вещи, типа хоткеев, звука, работы с буфером обмена). Но для тех же микросервисов он хорош и гораздо проще С++ в использовании и освоении (в полном объёме).
0
Sign up to leave a comment.
Интерфейсы как абстрактные типы данных в Go