«Предпочитайте композицию наследованию»
Это название главы 16 «Эффективная Java».
Также в Go мы должны следовать этому, используя встраивание структуры или интерфейса. И кажется, что это рекомендуется для нескольких документов, таких как EffectiveGo, что относится к стилю встраивания-композиции. (https://golang.org/doc/efficient_go.html#embedding)
Итак, давайте узнаем об этом вместе, просмотрев некоторые коды.
Во-первых, если подумать о простой библиотеке логгера, у логгера есть несколько особенностей, как показано ниже.
- Форматирование входной строки
- Запись/сброс журналов в выходной поток
Конечно, вы могли бы подумать, что любые спецификации — это хорошо, но в данном случае опустите их для ясности.
Хорошо, мы могли бы указать некоторые особенности «логгера».
Далее, выразить их в коде Go, интерфейсы двух особенностей могут быть закодированы, как показано ниже.
type Formatter interface { Format(s string) string } type Writer interface { Write(s string) error }
(Да, возможно, вам не нравится мой код, да, это нормально. Вы пишете «свой» классный код.)
Затем в них будет встроен «логгер».
type Logger struct { f Formatter w Writer } func (l *Logger) Log(s string) { l.w.Write(l.f.Format(s)) }
Почему определенные как «f» и «w» не определены как экспортируемые элементы? это просто моя просьба, Formatter и Writer Logger принадлежат Logger. Это личное.
Далее воспользуемся этим логгером, напишем вот так весь код.
package main import ( "fmt" ) type Formatter interface { Format(s string) string } type Writer interface { Write(s string) error } type Logger struct { f Formatter w Writer } func (l *Logger) Log(s string) { l.w.Write(l.f.Format(s)) } type MyFormatter struct{} func (f *MyFormatter) Format(s string) string { return fmt.Sprintf("####%s####", s) } type MyWriter struct{} func (w *MyWriter) Write(s string) error { // to be simple, cut corner. fmt.Println(s) return nil } func main() { l := Logger{ f: &MyFormatter{}, w: &MyWriter{}, } l.Log("Hello, World") }
На практике я не буду определять Logger в основной функции, буду использовать Provider-Pattern.
type LoggerProvider struct{} func (p *LoggerProvider) Provide() *Logger { return &Logger{ f: &MyFormatter{}, w: &MyWriter{}, } }
Менеджер провайдера, если он вам нужен, это отличная дополнительная часть, но иногда лучше быть осторожным, «последняя капля переполняет чашу» каждый раз.
Заботиться.