«Предпочитайте композицию наследованию»

Это название главы 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{},
 }
}

Менеджер провайдера, если он вам нужен, это отличная дополнительная часть, но иногда лучше быть осторожным, «последняя капля переполняет чашу» каждый раз.

Заботиться.