Декоратор
Введение
Шаблон 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 более удобен для добавления функциональности в объекты вместо целых структур во время выполнения.С отделкой также можно динамически удалять добавленные функции.