Программирование программного обеспечения включает в себя различные шаблоны, предназначенные для решения общих задач. Знакомство с этими шаблонами имеет решающее значение, поскольку они обеспечивают решения повторяющихся проблем в процессе разработки.

В этом уроке мы рассмотрим несколько хорошо известных шаблонов, в том числе шаблоны Decorator, Delegation и Composite, с которыми я часто сталкивался.

Шаблон декоратора

Шаблон Decorator — это структурный шаблон проектирования, который позволяет добавлять поведение к отдельному объекту статически или динамически, не влияя на поведение других объектов того же класса.

В этом шаблоне мы создаем серию классов декораторов, которые используются для обертывания конкретных компонентов. Декораторы добавляют функциональность компонентам, сохраняя при этом возможность связывать несколько декораторов вместе.

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

package main

import "fmt"

// Coffee defines the base component
type Coffee interface {
 GetCost() int
 GetDescription() string
}

// SimpleCoffee is a concrete coffee type
type SimpleCoffee struct{}

func (c *SimpleCoffee) GetCost() int {
 return 100
}

func (c *SimpleCoffee) GetDescription() string {
 return "Simple Coffee"
}

// MilkDecorator adds milk to the coffee
type MilkDecorator struct {
 coffee Coffee
}

func (m *MilkDecorator) GetCost() int {
 return m.coffee.GetCost() + 20
}

func (m *MilkDecorator) GetDescription() string {
 return m.coffee.GetDescription() + ", Milk"
}

// SugarDecorator adds sugar to the coffee
type SugarDecorator struct {
 coffee Coffee
}

func (s *SugarDecorator) GetCost() int {
 return s.coffee.GetCost() + 10
}

func (s *SugarDecorator) GetDescription() string {
 return s.coffee.GetDescription() + ", Sugar"
}

func main() {
 // Create a simple coffee
 coffee := &SimpleCoffee{}

 // Decorate the coffee with milk
 milkCoffee := &MilkDecorator{coffee}

 // Decorate the milk coffee with sugar
 sweetMilkCoffee := &SugarDecorator{milkCoffee}

 fmt.Printf("Order: %s, Cost: $%d\n", sweetMilkCoffee.GetDescription(), sweetMilkCoffee.GetCost())
}

В этом примере у нас есть интерфейс Coffee, определяющий базовый компонент для разных видов кофе. SimpleCoffee — это конкретный тип кофе, реализующий базовый интерфейс Coffee.

Затем у нас есть два декоратора, MilkDecorator и SugarDecorator, которые добавляют в кофе молоко и сахар соответственно. Каждый декоратор встраивает Coffee и модифицирует методы GetCost и GetDescription, чтобы включить дополнительные затраты и описания.

В функции main мы создаем простой кофе, а затем украшаем его молоком и сахаром с помощью декораторов. Окончательный вывод будет:

Order: Simple Coffee, Milk, Sugar, Cost: $130

Шаблон делегирования

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

Вот пример шаблона делегирования, реализованного в Go:

package main

import "fmt"

// MediaPlayer defines the delegating object
type MediaPlayer struct {
 mediaPlayerDelegate MediaPlayerDelegate
}

// MediaPlayerDelegate defines the delegate interface
type MediaPlayerDelegate interface {
 PlayMedia(file string)
}

// AudioPlayer is a concrete delegate for playing audio files
type AudioPlayer struct{}

func (a *AudioPlayer) PlayMedia(file string) {
 fmt.Printf("Playing audio file: %s\n", file)
}

// VideoPlayer is another concrete delegate for playing video files
type VideoPlayer struct{}

func (v *VideoPlayer) PlayMedia(file string) {
 fmt.Printf("Playing video file: %s\n", file)
}

func main() {
 audioPlayer := &AudioPlayer{}
 videoPlayer := &VideoPlayer{}

 mediaPlayer := &MediaPlayer{mediaPlayerDelegate: audioPlayer}
 mediaPlayer.PlayMedia("song.mp3")

 mediaPlayer.mediaPlayerDelegate = videoPlayer
 mediaPlayer.PlayMedia("movie.mp4")
}

В этом примере у нас есть интерфейс MediaPlayerDelegate, определяющий обязанности, которые можно делегировать, в данном случае воспроизведение медиафайлов. AudioPlayer и VideoPlayer являются конкретными реализациями этого интерфейса, каждая из которых обрабатывает аудио- и видеофайлы соответственно.

Структура MediaPlayer — это объект делегирования, содержащий ссылку на делегата через поле mediaPlayerDelegate. Он делегирует задачу воспроизведения медиафайлов делегату.

В функции main мы создаем экземпляры AudioPlayer и VideoPlayer. Затем мы создаем MediaPlayer, который начинается с делегата AudioPlayer и воспроизводит аудиофайл. Позже мы переключим делегата на VideoPlayer и воспроизведем видеофайл.

Когда мы запустим код, мы увидим следующий вывод:

Playing audio file: song.mp3
Playing video file: movie.mp4

Композитный шаблон

Шаблон Composite — это структурный шаблон проектирования, который позволяет объединять объекты в древовидные структуры для представления иерархий часть-целое. Composite позволяет клиентам обрабатывать отдельные объекты и композиции объектов единообразно.

Вот пример шаблона Composite в Go с использованием структуры файловой системы в качестве контекста:

package main

import "fmt"

// Component is the common interface for both leaf and composite objects
type Component interface {
 Display(indentation string)
}

// File is a leaf object that represents a file
type File struct {
 name string
}

func (f *File) Display(indentation string) {
 fmt.Println(indentation + f.name)
}

// Directory is a composite object that can hold files and subdirectories
type Directory struct {
 name       string
 components []Component
}

func (d *Directory) Add(component Component) {
 d.components = append(d.components, component)
}

func (d *Directory) Display(indentation string) {
 fmt.Println(indentation + "Directory: " + d.name)
 for _, component := range d.components {
  component.Display(indentation + "  ")
 }
}

func main() {
 rootDirectory := &Directory{name: "Root"}
 textFilesDirectory := &Directory{name: "Text Files"}
 imageFilesDirectory := &Directory{name: "Image Files"}

 file1 := &File{name: "file1.txt"}
 file2 := &File{name: "file2.txt"}
 file3 := &File{name: "file3.png"}
 file4 := &File{name: "file4.png"}

 textFilesDirectory.Add(file1)
 textFilesDirectory.Add(file2)
 imageFilesDirectory.Add(file3)
 imageFilesDirectory.Add(file4)

 rootDirectory.Add(textFilesDirectory)
 rootDirectory.Add(imageFilesDirectory)

 rootDirectory.Display("")
}

В этом примере у нас есть интерфейс Component, который определяет общие методы как для листовых объектов (File), так и для составных объектов (Directory).

Структура File — это конечный объект, представляющий файл. Он реализует метод Display для отображения своего имени.

Структура Directory — это составной объект, который может содержать файлы и другие каталоги. Он имеет массив из Component объектов и методов для добавления компонентов и отображения содержимого каталога.

В функции main мы создаем иерархию каталогов и файлов, а затем вызываем метод Display для корневого каталога, чтобы проиллюстрировать структуру.

Когда мы запустим код, мы увидим вывод:

Directory: Root
  Directory: Text Files
    file1.txt
    file2.txt
  Directory: Image Files
    file3.png
    file4.png

В этом уроке мы рассмотрели три известных шаблона: шаблон декоратора, который позволяет динамически настраивать объекты путем наложения декораторов; шаблон Delegate, позволяющий объектам делегировать задачи другим объектам; и шаблон Composite, упрощающий создание иерархических структур из отдельных и составных объектов. Понимая и эффективно используя эти шаблоны, разработчики могут улучшить модульность кода, возможность повторного использования и удобство сопровождения, что в конечном итоге приведет к созданию более надежных и эффективных программных решений.

Если вы найдете эту информацию полезной, пожалуйста, поддержите меня и следите за обновлениями.

Спасибо, что дочитали до конца. Пожалуйста, следите за автором и этой публикацией. Посетите Stackademic, чтобы узнать больше о том, как мы демократизируем бесплатное обучение программированию по всему миру.