Декоратор

Введение

Шаблон Decorator добавляет новые функции к существующему объекту без изменения его структуры.Это структурный шаблон, поскольку этот шаблон действует как оболочка существующего класса.

Инстантатор - структура декоратора, которая украшает (обертывает) исходный объект и обеспечивает дополнительную функциональность, сохраняя при этом свою подпись методов неповрежденной.

Цель

  • Прилагайте дополнительные обязанности к объекту динамически.
  • Декораторы обеспечивают гибкую альтернативу наследованию для расширения функциональности.
  • Обернуть подарок, положить его в коробку и обернуть коробку.

Схема проектирования

Шаблон Decorator имеет следующие объекты:

  • Component определяет интерфейс для объектов, которые могут иметь обязанности, добавленные к ним динамически.
  • ConcreteComponent определяет объект, к которому могут быть присоединены дополнительные обязанности.
  • Decorator поддерживает ссылку на объект Component и определяет интерфейс, соответствующий интерфейсу Component.
  • ConcreteDecorator добавляет ответственность перед компонентом.

Реализация

Мы изучаем использование шаблона декоратора в следующем примере, в котором мы будем расширять существующий объект, который извлекает данные из веб-службы.Мы украсим его, добавив возможности автоматического отключения без изменения интерфейса структуры.

Позволяет иметьFetcherинтерфейс, который определяет контракт для получения некоторых данных из разных источников.

package configurer

// Config provides a configuration of microservice
type Config struct {
    workDir string
    user    string
}

// NewConfig create a new config
func NewConfig(user string, workDir string) Config {
    return Config{
        user:    user,
        workDir: workDir,
    }
}

// WithWorkDir creates a copy of Config with the provided working directory
func (c Config) WithWorkDir(dir string) Config {
    c.workDir = dir
    return c
}

// WithUser creates a copy of Config with the provided user
func (c Config) WithUser(user string) Config {
    c.user = user
    return c
}

Конкретной реализациейFetcherинтерфейса являетсяRepositoryструктура, которая предоставляет некоторые фиктивные данные, если предоставленные аргументы не пусты, иначе возвращает ошибку.СтруктураRepositoryявляется конкретным компонентом в контексте шаблона Decorator.

config := configurer.NewConfig("guest", "/home/guest")
rootConfig := config.WithUser("root").WithWorkDir("/root")

fmt.Println("Guest Config", config)
fmt.Println("Root Config", rootConfig)

RetrierСтруктура является декоратором ,который добавляет возможности автоматического выключателя к любому компоненту ,который реализуетFetcherинтерфейс.УRetrierэтого есть несколько свойств, которые позволяют это.RetryCountСвойство определяет количество раз ,что retrier должен попытаться извлечь ,если есть ошибка.WaitIntervalСвойство определяет интервал между каждой повторной попыткой.FetcherСвойство указывает на объект ,который оформлен.ВRetrierвызовахFetchфункции из декорированного объекта ,пока не завершится успешно или превышать политику повторных попыток.

// Element represents an element in document object model
type Element struct {
    text     string
    parent   Node
    children []Node
}

// NewElement makes a new element
func NewElement(text string) *Element {
    return &Element{
        text:     text,
        parent:   nil,
        children: make([]Node, 0),
    }
}

// Parent returns the element parent
func (e *Element) Parent() Node {
    return e.parent
}

// SetParent sets the element parent
func (e *Element) SetParent(node Node) {
    e.parent = node
}

// Children returns the element children elements
func (e *Element) Children() []Node {
    return e.children
}

// AddChild adds a child element
func (e *Element) AddChild(child Node) {
    copy := child.Clone()
    copy.SetParent(e)
    e.children = append(e.children, copy)
}

// Clone makes a copy of particular element. Note that the element becomes a
// root of new orphan tree
func (e *Element) Clone() Node {
    copy := &Element{
        text:     e.text,
        parent:   nil,
        children: make([]Node, 0),
    }
    for _, child := range e.children {
        copy.AddChild(child)
    }
    return copy
}

// String returns string representation of element
func (e *Element) String() string {
    buffer := bytes.NewBufferString(e.text)

    for _, c := range e.Children() {
        text := c.String()
        fmt.Fprintf(buffer, "\n %s", text)
    }

    return buffer.String()
}

Затем мы можем добавить новые возможности повтора, обернувRepositoryэкземпляр с помощьюRetrier:

// Node a document object model node
type Node interface {
    // Strings returns nodes text representation
    String() string
    // Parent returns the node parent
    Parent() Node
    // SetParent sets the node parent
    SetParent(node Node)
    // Children returns the node children nodes
    Children() []Node
    // AddChild adds a child node
    AddChild(child Node)
    // Clone clones a node
    Clone() Node
}

решение

Шаблон Decorator более удобен для добавления функциональности в объекты вместо целых структур во время выполнения.С отделкой также можно динамически удалять добавленные функции.

results matching ""

    No results matching ""