Узнайте о 10 самых классических шаблонах проектирования в одной статье.
Узнайте о 10 самых классических шаблонах проектирования в одной статье.

Шаблоны проектирования программного обеспечения — это набор классифицированных и каталогизированных сводок опыта проектирования кода, которые используются неоднократно и известны большинству людей. Его значение состоит в том, что эти шаблоны представляют собой ценный опыт, обобщенный многими программистами после длительного периода проб и ошибок, который может помочь нам улучшить возможность повторного использования, читабельность и надежность кода. Эта статья была написана Ван Шуньчи, инженером по бизнес-безопасности в Tencent Cloud Tianyu. В ней обобщаются характеристики, преимущества, недостатки и сценарии применения 10 классических шаблонов проектирования программного обеспечения, а также приводятся соответствующие примеры кода.

Следите за разработчиками Tencent Cloud и заранее получайте техническую информацию из первых рук👇

01. Шаблон «Синглтон»

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

Функции:

  • Существует только один экземпляр объекта.
  • Должен сделать это самсоздавать Примеробъект。
  • Необходимо предоставить глобальную точку доступа к экземпляру.

преимущество:

  • Обеспечьте глобальную уникальность ресурсов или состояния внутри приложения.
  • Уменьшить потребление ресурсов,Повышение эффективности системы.

недостаток:

  • Антимодульность,потому чтодля Синглтонобъект Необходимость ссылки от нескольких клиентов,Это нарушает высокую связность и низкую связанность.изпринципы проектирования。
  • Трудно проверить,потому чтодля Синглтонобъектиз Жизненный цикл такой же, как у приложения.,Это затрудняет проведение изолированного тестирования в рамках модульных тестов.

Сценарии применения:

  • Менеджер конфигурации:в приложении,Для управления информацией о конфигурации обычно требуется только один экземпляр.,Это гарантирует, что информация о конфигурацииизпоследовательность。
  • Пул соединений:Пул подключений к базе данных должен ограничивать подключения к базе данных.изколичество,чтобы избежать слишком многогоиз Соединение потребляет ресурсы。
  • Регистратор:бревносистема Обычно тольконуждатьсяодин Примерзаписать заявкуизбревноинформация,чтобы избежать регистрации сообщенийизизбыточность и путаница。
  • Менеджер оборудования:Для некоторых аппаратных устройств,нравиться Распечататьмашина или сканер,Может просто нужен менеджер, чтобы контролировать ихиздоступ。
  • Управление статусом заявки:в некоторых приложениях,нужен глобальныйиз Управление статусами,Например, управление сеансами пользователей или статус проверки разрешений.
Язык кода:javascript
копировать
// Определите структуру Singleton для хранения данных экземпляра синглтона.
type singleton struct {
 value string // Здесь могут храниться любые данные одноэлементного объекта.
}

// Определите экземпляр глобальной переменной для хранения экземпляра синглтона.
var instance *singleton

// Функция getInstance используется для получения экземпляра синглтона.
// Если экземпляр равен нулю, создайте новый экземпляр Singleton.
// В противном случае верните существующий экземпляр
func getInstance() *singleton {
 if instance == nil {
     instance = &singleton{value: "unique instance"} // Инициализируйте экземпляр синглтона здесь
 }
 return instance // Вернуть экземпляр синглтона
}

func main() {
 // Получить экземпляр синглтона
 singletonInstance := getInstance()
 fmt.Println(singletonInstance.value) // Выход: unique instance

 // снова Получить экземпляр синглтона,вернется то же самоеиз Пример
 anotherInstance := getInstance()
 if singletonInstance == anotherInstance {
     fmt.Println("Both instances are the same") // Выход: Both instances are the same
 }
}

В параллельной среде, если нет соответствующего механизма синхронизации, несколько goroutine могут быть обнаружены одновременноinstanceдляnilи попробуйсоздаватьновыйиз Пример,что приводит ксоздаватьнесколько Пример。для Чтобы решить эту проблему,Можно использоватьsync.Once,Это гарантирует, что в параллельной среде выполняется только одна операция инициализации.

Язык кода:javascript
копировать
// Определите структуру Singleton для хранения данных экземпляра синглтона.
type singleton struct {
    value string // Здесь могут храниться любые данные одноэлементного объекта.
}

// Определите объект Once, чтобы гарантировать, что операция инициализации выполняется только один раз.
var once sync.Once

// Определите экземпляр глобальной переменной для хранения экземпляра синглтона.
var instance *singleton

// Функция инициализации, вызываемая Once.Do
func initSingleton() {
    instance = &singleton{value: "unique instance"} // Инициализируйте экземпляр синглтона здесь
}

// Функция getInstance используется для получения экземпляра синглтона.
func getInstance() *singleton {
    // Выполните initSingleton, чтобы гарантировать, что экземпляр инициализируется только один раз.
    once.Do(initSingleton)
    return instance // Вернуть экземпляр синглтона
}

func main() {
    // Получить экземпляр синглтона
    singletonInstance := getInstance()
    fmt.Println(singletonInstance.value) // Выход: unique instance

    // снова Получить экземпляр синглтона,вернется то же самоеиз Пример
    anotherInstance := getInstance()
    if singletonInstance == anotherInstance {
        fmt.Println("Both instances are the same") // Выход: Both instances are the same
    }
    
    // Тестирование одноэлементного режима в параллельной среде
    var wg sync.WaitGroup
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            singletonInstance := getInstance()
            fmt.Println(singletonInstance.value)
        }()
    }
    wg.Wait()
}

02. Фабричный узор

Шаблон «Фабрика» — это шаблон творческого проектирования, который инкапсулирует процесс создания объектов, а подкласс решает, экземпляр какого класса создавать. Этот шаблон делает структуру кода более понятной и позволяет легко заменять или расширять классы продуктов.

Функции:

  • Инкапсуляция:Воляобъектизсоздавать Процесс инкапсулирован в фабричный класс。
  • Расширяемость: благодаря наследованию и полиморфизму можно легко добавлять новые классы продуктов.
  • абстракция:Фабричный метод определяетсоздаватьобъектизинтерфейс,Но конкретныйобъектизсоздаватьреализовано подклассами。

преимущество:

  • Воляобъектизсоздавать Отдельно от использования,Улучшенная модульная комнатаизнезависимость。
  • Его легко расширить. При добавлении новых категорий продуктов нет необходимости изменять существующий код, и он соответствует принципу открытия и закрытия.

недостаток:

  • Каждый раз при добавлении класса продукции необходимо добавлять определенный класс фабрики, что может привести к резкому увеличению количества классов.
  • Фабричный класс централизует всю логику создания экземпляров, что может привести к тому, что фабричный класс будет слишком большим.

Сценарии применения:

  • Подключение к базе данных:По разнымиз Тип базы данных,⦂ MySQL, PostgreSQL.,создаватьсоответствующийиз Подключение к базе данныхобъект。
  • Компоненты графического интерфейса:в разработке графического пользовательского интерфейса,другойиздействоватьсистемавозможныйнуждатьсядругойизкомпонентывыполнить,Заводской образец Может По разнымплатформасоздаватьсоответствующийизкомпоненты。
  • Платежный шлюз:По разнымиз Способ оплаты,Например, кредитная карта, PayPal, оплата WeChat,создаватьсоответствующийизобработка платежейобъект。
  • Обработка изображения:в программе обработки изображений,По разнымиз Формат файла,нравиться JPEG, PNG, создайте соответствующий процессор изображений.
Язык кода:javascript
копировать
// Определите интерфейсProduct, который объявляет все операции, которые должен реализовать конкретный объект продукта.
type Product interface {
 operation() // Эксплуатация продукта объект
}

// Определите конкретный продукт ConcreteProductA и реализуйте интерфейс Productinterface.
type ConcreteProductA struct{}
func (p *ConcreteProductA) operation() {
 fmt.Println("Operation of ConcreteProductA")
}

// Определите другой конкретный продукт ConcreteProductB, который также реализует интерфейс Productinterface.
type ConcreteProductB struct{}
func (p *ConcreteProductB) operation() {
 fmt.Println("Operation of ConcreteProductB")
}

// Определите абстрактную фабрику Creator, которая объявляет фабричный метод FactoryMethod, который используется для создания объекта продуктов.
type Creator interface {
 factoryMethod() Product // Фабричный метод создания объекта продукции
}

// Определите конкретную фабрику CreatorA, которая реализует интерфейс Creator.
type CreatorA struct{}
func (c *CreatorA) factoryMethod() Product {
 return &ConcreteProductA{} // Бетонная фабрика CreatorA возвращает экземпляр ConcreteProductA.
}

// Определите еще одну конкретную фабрику CreatorB, которая также реализует интерфейс Creator.
type CreatorB struct{}
func (c *CreatorB) factoryMethod() Product {
 return &ConcreteProductB{} // Бетонная фабрика CreatorB возвращает экземпляр ConcreteProductB.
}

func main() {
 // Создайте экземпляр конкретной фабрики CreatorA.
 creatorA := &CreatorA{}
 productA := creatorA.factoryMethod()
 productA.operation() // Вызов операции продукта А

 // Создайте экземпляр конкретной фабрики CreatorB.
 creatorB := &CreatorB{}
 productB := creatorB.factoryMethod()
 productB.operation() // Назовите операцию продукта B
}

03. Модель наблюдателя

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

Функции:

  • Отношения «один ко многим». У субъекта может быть несколько наблюдателей.
  • абстрактная связь:наблюдательитемамеждудаабстрактная связьиз,Увеличиватьновыйиз Наблюдатели не повлияют на существующиеизсистема。
  • Динамическая связь: наблюдатели могут присоединиться или выйти в любое время.

преимущество:

  • уменьшенныйобъектмеждуиз Степень сцепления,темаинаблюдательмеждуда松散耦合из。
  • Хорошая масштабируемость, добавление новых классов наблюдателей или субъектов не влияет на существующие классы.

недостаток:

  • Когда много наблюдателей,уведомитьиз Распространение может вызвать проблемы с производительностью.。
  • еслинаблюдательитемамеждуиз Зависимости слишком сложны,Это затруднит обслуживание системы.

Сценарии применения:

  • Система мониторинга событий:существовать GUI В приложении компоненты пользовательского интерфейса (такие как кнопки, текстовые поля и т. д.) могут выступать в качестве наблюдателей для прослушивания событий ввода пользователя.
  • Обновления пользовательского интерфейса:в приложении,Когда меняется модель данных,Интерфейс необходимо соответствующим образом обновить.,Этот процесс можно автоматизировать с помощью шаблона наблюдателя.
  • Система сообщений:существоватьпрограммное обеспечение для обмена мгновенными сообщениямисередина,когда приходят новые сообщения,всесуществовать Проволокаизпользователь(наблюдатель)получитуведомить。
  • Фондовый рынок:Обновления цен на акцииновыйчас,Все подписчики этой акцииизинвестор(наблюдатель)получит最новый价格информация。
  • Мониторинг ресурсов:существоватьсистема В инструменте мониторинга,Когда системные ресурсы (такие как ЦП, использование памяти) превышают установленный порог.,Система мониторинга (наблюдатели) уведомляется и принимает соответствующие меры.
Язык кода:javascript
копировать
// Определите интерфейс Observer, который объявляет метод Update, который наблюдатель должен реализовать.
type Observer interface {
 Update(string) // Этот метод будет вызываться при изменении статуса темы.
}

// Определите структуру субъекта, которая содержит список наблюдателей и методы для добавления или уведомления наблюдателей.
type Subject struct {
 observers []Observer // Хранить список наблюдателей
}

// Метод Attach используется для добавления наблюдателя в список наблюдателей.
func (s *Subject) Attach(observer Observer) {
 s.observers = append(s.observers, observer)
}

// Метод Notify используется для уведомления всех наблюдателей об изменениях состояния темы.
func (s *Subject) Notify(message string) {
 for _, observer := range s.observers {
     observer.Update(message) // Вызовите метод Update каждого наблюдателя.
 }
}

// Определите конкретного наблюдателя ConcreteObserver, который реализует интерфейс Observer.
type ConcreteObserverA struct {
 name string
}

// Реализуйте метод Update интерфейса Observer.
func (c *ConcreteObserverA) Update(message string) {
 fmt.Printf("%s received message: %s\n", c.name, message)
}

func main() {
 // Создать объект темы
 subject := &Subject{}

 // Создайте конкретный объект-наблюдатель
 observerA := &ConcreteObserverA{name: "Observer A"}

 // Добавить наблюдателя в список наблюдателей темы
 subject.Attach(observerA)

 // Уведомлять всех наблюдателей об изменении состояния темы.
 subject.Notify("State changed to State 1")
}

04. Узор-декоратор

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

Функции:

  • Динамическое расширение: обязанности могут быть динамически добавлены к объекту во время выполнения.
  • Прозрачность:Режим декоратора не меняетсяобъектизинтерфейс,потому что此верно客户端Приходить说да透明из。
  • Гибкость: может использоваться в сочетании с несколькими декораторами.,дляобъект Добавьте несколько обязанностей。

преимущество:

  • Увеличиватьобъектиз Ответственность динамичнаиз、Может быть отозваниз。
  • Вы можете обернуть объект несколькими декораторами, добавив несколько обязанностей.
  • Декораторы и объект могут различаться независимо.,не связаны друг с другом.

недостаток:

  • Чрезмерное использование шаблона декоратора может усложнить систему.,Непонятно.
  • Это может привести к вызову нескольких уровней декоратора, что повлияет на производительность.

Сценарии применения:

  • Ведение журнала:существовать Не изменяйте оригиналобъектизпо сути,Добавьте функцию ведения журнала.
  • кэш:дляобъектиз Некоторые методы добавляют возможности кэширования.,для улучшения производительности.
  • Контроль безопасности:дляобъектдобавить вдоступконтроль,Например, проверка разрешений.
  • Обработка транзакции:длябаза данныхдействоватьдобавить в事务Функции управления。
  • Мониторинг производительности:дляобъектиз Способ добавления функции мониторинга производительности,Для анализа узких мест производительности.
  • Управление ресурсами:для Использование ресурсов добавляет дополнительныеиз Функции управления,нравитьсяпул соединенийизуправлять。
Язык кода:javascript
копировать
// Определите Componentinterface, который является базовым классом для всех компонентов и декораторов.
type Component interface {
 operation() // Операция, выполняемая компонентом
}

// Определите конкретный компонент ConcreteComponent и реализуйте Componentinterface.
type ConcreteComponent struct{}
func (c *ConcreteComponent) operation() {
 fmt.Println("ConcreteComponent: performing basic operation")
}

// Определите абстрактную структуру Decorator, которая содержит поле типа Componentinterface.
type Decorator struct {
 component Component // Используется для объединения компонентов интерфейса
}

// Реализуйте метод работы Декоратора и вызовите метод работы его Компонента.
func (d *Decorator) operation() {
 if d.component != nil {
     d.component.operation() // Вызов декорированной операции
 }
}

// Определите конкретный декоратор ConcreteDecoratorA, который встраивает структуру Decorator.
type ConcreteDecoratorA struct {
 Decorator // Наследовать Decorator для реализации функций оформления.
}

// Реализуйте метод операции для ConcreteDecoratorA и добавьте дополнительные обязанности.
func (cda *ConcreteDecoratorA) operation() {
 cda.Decorator.operation() // Прежде всего декорированной операции
 fmt.Println("ConcreteDecoratorA: added additional responsibilities")
}

func main() {
 // Создание конкретных компонентов
 component := &ConcreteComponent{}

 // Создавайте декораторы и связывайте определенные компоненты
 decoratorA := &ConcreteDecoratorA{Decorator{component}}

 // Выполнение операций с декорированными компонентами
 decoratorA.operation()
}

05. Стратегический шаблон

Шаблон стратегии — это шаблон поведенческого проектирования, который определяет ряд алгоритмов и инкапсулирует каждый алгоритм так, чтобы их можно было заменять друг другом. Паттерн «Стратегия» делает алгоритм независимым от использующего его клиента.

Функции:

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

преимущество:

  • Изменения алгоритма не зависят от клиента, использующего алгоритм.
  • Легко добавляйте новые алгоритмы, не затрагивая клиентов.

недостаток:

  • Клиенты должны понимать различия во всех классах политик, чтобы использовать соответствующую политику.

Сценарии применения:

  • Выбор алгоритма:в приложении,По разнымиз Выбор бизнес-требованийдругойизалгоритм。
  • Способ оплаты:существовать电子商务платформа,в соответствии спользователь Выберите, чтобы предложитьдругойиз Способ оплаты。
  • Алгоритм сортировки:существовать Обработка данныхсередина,По разнымиз Выбор функции данныхдругойизсортироватьалгоритм。
  • Поиск пути:существоватькартографический сервиссередина,По разнымиз Критерии оптимизации(нравитьсячас间最短、кратчайшее расстояние)выбиратьдругойиз Поиск путиалгоритм。
  • Игровой ИИ:существоватьигра В разработке,другойиз Используется врагами или персонажамидругойиз AI Стратегия.
Язык кода:javascript
копировать
// Определите интерфейс Strategy, который объявляет методы алгоритма, которые должны реализовать все конкретные стратегии.
type Strategy interface {
 algorithm() // алгоритмический подход к стратегии
}

// Определите конкретную стратегию ConcreteStrategyA и реализуйте Strategyinterface.
type ConcreteStrategyA struct{}
func (c *ConcreteStrategyA) algorithm() {
 fmt.Println("Executing Algorithm A")
}

// Определите еще одну конкретную стратегию ConcreteStrategyB, которая также реализует интерфейс Strategy.
type ConcreteStrategyB struct{}
func (c *ConcreteStrategyB) algorithm() {
 fmt.Println("Executing Algorithm B")
}

// Определите структуру Context, которая содержит поле типа Strategyinterface.
type Context struct {
 strategy Strategy // Используется для хранения текущей используемой политики.
}

// Метод выполнения стратегии, вызов метода алгоритма через поле стратегии в контексте.
func (c *Context) executeStrategy() {
 c.strategy.algorithm() // Алгоритм реализации текущей стратегии
}

func main() {
 // CreateContextобъект
 context := &Context{}

 // Создать конкретную стратегию объекта
 strategyA := &ConcreteStrategyA{}
 strategyB := &ConcreteStrategyB{}

 // Установите политику контекста на политику A.
 context.strategy = strategyA
 context.executeStrategy() // Выход: Executing Algorithm A

 // Изменить стратегию на стратегию B
 context.strategy = strategyB
 context.executeStrategy() // Выход: Executing Algorithm B
}

06. Шаблон адаптера

Шаблон «Адаптер» — это структурный шаблон проектирования, используемый для обеспечения совместной работы несовместимых в противном случае интерфейсов. Обычно при этом один клиент использует определенный ожидаемый интерфейс, а другой класс или компонент предоставляет другой интерфейс. Шаблон «Адаптер» преобразует интерфейс класса в другой интерфейс, ожидаемый клиентом, путем создания промежуточного уровня (адаптера).

Функции:

  • интерфейс Конвертировать:Шаблон адаптера обеспечивает Воляодиндобрыйизинтерфейс Конвертироватьв другой видинтерфейсиз Способ。
  • совместимость:решеноинтерфейс Не совместимоизвопрос,сделать невозможной совместную работуиз Классы могут работать вместе。

преимущество:

  • Увеличивать Понятнодобрыйизсовместимость,чтобы они могли работать вместе,Даже если ониизинтерфейс Не совместимо。
  • Клиентский код не нуждается в модификации и взаимодействует с целевым классом через адаптер.

недостаток:

  • Чрезмерное использование шаблона адаптера может усложнить систему.,Трудно понять и поддерживать.
  • Адаптеры могут привести к снижению производительности, особенно если методы адаптера необходимо вызывать часто.

Сценарии применения:

  • Интеграция различных систем:когдануждаться Волядва использованиядругойинтерфейсизсистема При интеграции,Можно использовать режим адаптера.
  • Интеграция сторонних библиотек:При использовании сторонней библиотеки,Но когда его интерфейс несовместим с существующей системой,Интеграцию можно выполнить через шаблон адаптера.
  • Аппаратное управление устройством:существовать Аппаратное оборудованиеконтрольполе,другойиз设备возможный有другойизконтрольинтерфейс,Шаблон адаптера можно использовать для унификации этих интерфейсов.
  • Миграция старых и новых систем:существоватьновыйстарыйсистема В процессе миграции,старыйсистемасерединаизкомпонентывозможныйнуждатьсяприспособлениеновыйсистемаизинтерфейс。
  • Модульная конструкция:существовать Модульная конструкциясередина,Режим адаптера можно использовать для подключения различных модулей.,Даже если ониизинтерфейс Не совместимо。
Язык кода:javascript
копировать
// Определение Целевой интерфейс представляет собой конкретный интерфейс, связанный с доменом, используемый клиентом.
type Target interface {
 request() // Метод, который клиент ожидает вызвать
}

// Определите существующий класс Adaptee, который имеет собственный интерфейс.
type Adaptee struct{}
func (a *Adaptee) specificRequest() {
 fmt.Println("Adaptee performs a specific request")
}

// Определите структуру адаптера, которая служит мостом между классами Target и Adaptee.
type Adapter struct {
 adaptee *Adaptee // Цитата Adapteeобъект
}

// Адаптер реализует метод запроса целевого интерфейса.
// Этот метод внутренне делегирует метод specificRequest Adaptee.
func (a *Adapter) request() {
 if a.adaptee != nil {
     a.adaptee.specificRequest() // Делегированный метод вызова Adaptee
 }
}

func main() {
 // Создать объект Adaptee
 adaptee := &Adaptee{}

 // Создайте объект Adaptee и внедрите объект Adaptee.
 adapter := &Adapter{adaptee: adaptee}

 // Клиент использует Target, который реализуется через адаптер.
 var target Target = adapter
 target.request() // Метод вызова Adaptee через адаптер
}

07. Шаблон прокси

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

Функции:

  • Косвенный доступ: через актерское мастерствообъект для косвенного доступа к исходному объекту.
  • Разделение обязанностей: Отделить логику управления от бизнес-логики, актерское мастерство объект отвечает за логику управления,Исходный объект отвечает за бизнес-логику.
  • Ленивая инициализация:актерское мастерство Можетсуществоватьнуждатьсячас才создаватьоригинальныйобъект,Реализуйте ленивую инициализацию.

преимущество:

  • уменьшенныйсистемаиз Степень сцепления,Улучшенныйобъектиз Управляемость。
  • Можетдляоригинальныйобъект Предоставить дополнительныеиз Безопасностьконтроль Или ленивая загрузка и т.д.действовать。
  • Увеличиватькодиз Масштабируемость,Можетсуществовать Не изменятьоригинальныйобъектизслучай,Представляяновыйизактерское мастерство класса для расширения функциональности.

недостаток:

  • Увеличивать Понятносистемаизсложность,Может усложнить конструкцию системы.
  • Может привести к увеличению производительности, особенно в актерском мастерстве. мастерствообъект Когда требуется сложная логика управления.

Сценарии применения:

  • Контроль доступа:существоватьнуждатьсявернообъектдоступвыполнять разрешенияконтрольчас,Вы можете использовать режим актерского мастерства.
  • Ленивая инициализация:Большое потребление ресурсовизобъект,Можно использоватьактерское Режим мастерства реализует отложенную загрузку.
  • Удаленный агент:дляудаленныйобъектили предоставлены сетевыми ресурсамиактерское мастерство,скрыватьобъектродыдругойадресное пространствоизфакт。
  • Виртуальный агент:длясложныйизобъектсоздаватьпростойизактерское мастерство для упрощения доступа.
  • Агент защиты:контрольвернооригинальныйобъектиздоступ,поставлятьдоступдо и послеиздополнительныйдействовать。
  • Умные цитаты:существоватьдоступобъект Подсчет ссылок,Автоматически освобождать ресурсы, когда на них больше нет ссылок.
Язык кода:javascript
копировать
// Определите интерфейс субъекта, который объявляет истинную тему и актерское мастерство. Тема мастерства, разделяемая интерфейсом.
type Subject interface {
 request() // Объявите метод запроса, настоящую тему и актёрское мастерство. Все темы мастерства будут реализовывать этот метод.
}

// RealSubject Структура реализована Subject интерфейс, представляет собой истинную тему.
type RealSubject struct{}

// RealSubject из request Метод реализован Subject интерфейсиз request метод,используется для выполнения фактическогоиздействовать。
func (r *RealSubject) request() {
 fmt.Println("Real Subject") // Распечатать "Real Subject" Указывает, что вызывается реальная тема.
}

// Proxy Структура содержит указатель на RealSubject изуказатель,это такдляактерское мастерствотема。
type Proxy struct {
 realSubject *RealSubject // актерское мастерствотема Включатьодинвернореальностьтемаиз Цитировать,исходныйдля nil。
}

// Proxy из request Метод реализован Subject интерфейсиз request метод.
// Этот метод сначала проверяет realSubject Это ноль, если да, создайте RealSubject из Пример。
// Затем позвоните realSubject из request метод, тем самым косвенно достигая Subject интерфейсиз request метод.
func (p *Proxy) request() {
 if p.realSubject == nil { // если realSubject для nil,Пока нет объясненийсоздаватьреальностьтемаиз Пример。
     p.realSubject = &RealSubject{} // создавать RealSubject из Пример,и назначьте его realSubject。
 }
 p.realSubject.request() // вызовреальностьтемаиз request метод.
}

08. Шаблон команды

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

Функции:

  • Инкапсуляция:командный режим Воля Запросить инкапсуляциюдляодинобъект,скрывать Понятно请求из Конкретные детали реализации。
  • Расширяемость: новые классы команд можно легко добавлять без изменения существующего кода.
  • Гибкость: команды объекта могут быть сохранены.、передача、очередь、Запишите и исправьте.

преимущество:

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

недостаток:

  • Классов команд может быть большое количество, особенно если логика реализации команд сложна.

Сценарии применения:

  • Обработка транзакции:существоватьнуждатьсяподдержка вопросовдействоватьизсистемасередина,Командный режим может инкапсулировать запросы транзакций.,поддержка вопросовиз Зафиксировать и откатить。
  • Отменить операцию:существоватьнуждаться Функция отменыизсистемасередина,Команда объект может хранить состояние,чтобы отменить операцию, если это необходимо.
  • Запрос журнала:существоватьнуждаться Записыватьпользовательдействоватьизсистемасередина,Команда объект может записывать журналы операций.,Используется для операций аудита или восстановления.
  • Система пакетной обработки:существовать Пакетная обработкасистемасередина,Командный объект может представлять задачу пакетной обработки.,поддержка задачиз Планирование и исполнение。
  • Запись макроса:существоватьнуждаться Функция записи макросовизсистемасередина,Команда объект может инкапсулировать серию операций.,Сформируйте макрокоманду.
Язык кода:javascript
копировать
// Определить команду интерфейса,Он заявляет, что все конкретные команды должны быть реализованы.изExecuteметод
type Command interface {
    Execute() // выполнить командуизметод
}

// определениеReceiverСтруктура,это Волявыполнить командаиз фактического запроса
type Receiver struct{}
func (r *Receiver) Action() {
    fmt.Println("Receiver: Action")
}

// Определите структуру ConcreteCommand, которая реализует интерфейс Command.
// каждыйконкретные инструкции都ВключатьодинReceiverиз Цитировать,Запросизполучатель
type ConcreteCommand struct {
    receiver *Receiver // Выполнение команды из приемника
}

// ConcreteCommandвыполнитьCommandинтерфейсизExecuteметод
// ДолженметодвызовReceiverизActionметод Приходить Выполнить запрос
func (c *ConcreteCommand) Execute() {
    c.receiver.Action() // Выполнить запрос
}

// определениеInvokerСтруктура,Он отвечает за вызов командобъектизExecuteметод
type Invoker struct {
    command Command // Сохранить объект команды
}

// вызов命令объектизExecuteметод
func (i *Invoker) Invoke() {
    i.command.Execute() // выполнить команду
}

func main() {
    // создаватьполучательобъект
    receiver := &Receiver{}

    // создать конкретный объект команды,и вводитьполучатель
    command := &ConcreteCommand{receiver: receiver}

    // создаватьзвонящийобъект,и вводитьконкретные инструкцииобъект
    invoker := &Invoker{command: command}

    // звонящийвыполнить команду
    invoker.Invoke() // Выход: Receiver: Action
}

09. Составной узор

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

Функции:

  • Иерархия части-целого: может содержать другие комбинации или листовые узлы для формирования древовидной структуры.
  • Согласованность: клиентский код может последовательно обрабатывать составные структуры и конечные узлы.

преимущество:

  • Упрощенный клиентский код,Клиенты могут единообразно обрабатывать комбинированные структуры и объекты.
  • Лучшее иерархическое представление, его легче расширять и поддерживать.

недостаток:

  • Конструкция более сложная,нуждаться Проектируйте правильнокомпонентыизинтерфейси класс。

Сценарии применения:

  • Файловая система:документсистемасерединаиздокументидокументпапка Можетформадревовидная структура,Папки могут содержать файлы и другие папки.
  • Организационная структура:компанияизорганизационная структура Можетвыражатьдлядревовидная структура,Каждый из этих отделов может содержать сотрудников и другие подотделы.
  • Компоненты графического интерфейса:в разработке графического пользовательского интерфейса,Компоненты могут содержать другие компоненты,формасложныйиз Структура интерфейса。
  • Распределенная система:существоватьраспределенныйсистемасередина,Ресурсы могут быть объединены в древовидную структуру.,для облегчения управления и доступа.
  • Планирование ресурсов предприятия (ERP):ERP системасередина,Изделия могут состоять из нескольких компонентов.,Части снова Может Разбейте это дальшедлясборочный узел。
Язык кода:javascript
копировать
// Определить интерфейс компонента,делатьдлякомбинациясерединаобъектизпоследовательностьпротокол
type Component interface {
 Operation() // осуществлятьдействоватьизметод
 Add(Component)    // Ккомбинациясерединадобавить в子узелизметод
 Remove(Component) // откомбинациясерединаудалить подпискуузелизметод
 GetChild(int) Component // Получить дочерние узлы на основе индексаизметод
}

// определениеLeafСтруктура,выражатькомбинациясерединаизлистовой узел
type Leaf struct {
 name string
}

// LeafвыполнитьComponentинтерфейсизOperationметод
func (l *Leaf) Operation() {
 fmt.Println("Leaf:", l.name)
}

// LeafвыполнитьComponentинтерфейсизAddметод,Листовые узлы не могут иметь дочерних узлов.,потому чтоэто здесь Может Нетвыполнитьили выдать ошибку
func (l *Leaf) Add(c Component) {
 fmt.Println("Cannot add to a leaf")
}

// LeafвыполнитьComponentинтерфейсизRemoveметод,Листовые узлы не могут иметь дочерних узлов.,потому чтоэто здесь Может Нетвыполнитьили выдать ошибку
func (l *Leaf) Remove(c Component) {
 fmt.Println("Cannot remove from a leaf")
}

// LeafвыполнитьComponentинтерфейсизGetChildметод,Листовые узлы не имеют дочерних узлов,Итак, здесь возвращается ноль
func (l *Leaf) GetChild(i int) Component {
 вернуть ноль
}

//Определяем составную структуру,выражатькомбинациясерединаиз Контейнерный узел
type Composite struct {
 name     string
 Children []Component // Сохраните список дочерних узлов
}

// CompositeвыполнитьComponentинтерфейсизOperationметод
func (c *Composite) Operation() {
 fmt.Println("Composite:", c.name)
 for _, child := range c.Children {
     child.Operation() // 递归вызов子узелизOperationметод
 }
}

// CompositeвыполнитьComponentинтерфейсизAddметод,КChildrenсписоксерединадобавить в子узел
func (c *Composite) Add(component Component) {
 c.Children = append(c.Children, component)
}

// CompositeвыполнитьComponentинтерфейсизRemoveметод,отChildrenсписоксерединаудалить подпискуузел
func (c *Composite) Remove(component Component) {
 for i, child := range c.Children {
     if child == component {
         c.Children = append(c.Children[:i], c.Children[i+1:]...)
         break
     }
 }
}

// CompositeвыполнитьComponentинтерфейсизGetChildметод,Получить дочерние узлы на основе индекса
func (c *Composite) GetChild(i int) Component {
 if i < 0 || i >= len(c.Children) {
     return nil // Индекс вне диапазона, вернуть ноль
 }
 return c.Children[i]
}

func main() {
 // создаватьлистовой узел
 leafA := &Leaf{name: "Leaf A"}
 leafB := &Leaf{name: "Leaf B"}

 // создатькомбинированный узел
 composite := &Composite{name: "Composite Root"}
 composite.Add(leafA) // Добавьте листовой узел A в комбинацию
 composite.Add(leafB) // Добавьте листовой узел B в композицию.

 // осуществлятькомбинацияузелиздействовать
 composite.Operation()
}

10. Шаблон «Итератор»

Шаблон «Итератор» — это шаблон поведенческого проектирования, который позволяет последовательно получать доступ к элементам агрегатного объекта, не раскрывая его внутреннее представление. Шаблон Iterator предоставляет способ перемещения элементов через абстрактные итераторы, позволяя вам перемещаться по коллекции, не зная конкретного типа коллекции.

Функции:

  • Процесс обхода абстракции:Итераторопределение Понятнотраверсэлементизинтерфейс。
  • Поддержка несколькихтраверс Способ:другойиз Итератор Можетвыполнитьдругойизтраверс Стратегия.
  • полимеризацияобъект Отделение от итераторов:полимеризацияобъект Не нужно знать итераторыизспецифическийвыполнить。

преимущество:

  • Абстрагирует доступ к коллекции, чтобы клиентский код был независим от внутреннего представления коллекции.
  • Могут быть предоставлены несколько методов обхода, например обход в прямом или обратном порядке.
  • Гибкость коллекции увеличивается, и можно вводить новые методы обхода без изменения класса коллекции.

недостаток:

  • Увеличивать Понятносистемаизсложность,нуждатьсядлякаждыйполимеризациядобрый设计Итератордобрый。
  • Для реализации итератора требуется дополнительный код.

Сценарии применения:

  • Пройдитесь по коллекции:существоватьнуждатьсятраверс集合элементизсистемасередина,Шаблон итератора обеспечивает общееизтраверсмеханизм。
  • Структура данных:существоватьвыполнитьсложныйизструктура данныхнравиться Дерево、график изохроны,Итератор模式Может用Приходитьтраверсструктурасерединаизузел。
  • Запрос к базе данных:существоватьбаза данных查询середина,Итераторы можно использовать для доступа к результатам запроса поэлементно.
  • пользовательский интерфейс:существоватьпользовательинтерфейс В разработке,Итераторы можно использовать для перемещения по элементам интерфейса.
  • Доступ к многомерному массиву:существоватьнуждатьсядоступ多维数组элементизсистемасередина,Итератор Можетпоставлять一种顺序доступиз Способ。
Язык кода:javascript
копировать
// Определить итератор интерфейса,это声明Понятно Итератор必须выполнитьизNextиCurrentметод
type Iterator interface {
 Next() bool   // Перейти к следующему элементу и узнать, был ли переход успешным.
 Current() interface{} // Вернуть текущий элемент
}

// Определите структуру ConcreteIterator, которая реализует интерфейс Iterator.
type ConcreteIterator struct {
 items []string   // хранилищеполимеризацияобъектизсписок элементов
 index int        // Текущая итерация по индексу элемента
}

// Реализация следующего метода, используемая для перехода к следующему элементу.
func (c *ConcreteIterator) Next() bool {
 if c.index < len(c.items) {
     c.index++ // приращение индекса
     return true
 }
 return false // если Индекс вне диапазона,вернуть ложь
}

// Текущая реализация метода,используется для Вернуть текущий элемент
func (c *ConcreteIterator) Current() interface{} {
 if c.index > 0 && c.index <= len(c.items) {
     return c.items[c.index-1] // Возвращает текущий индекс элемента
 }
 return nil // если索引Нетсуществоватьв пределах досягаемости,Возврат ноль
}

//определить агрегатный интерфейс,означает объект агрегации,это Воля Ответственныйсоздавать Итератор
type Aggregate interface {
 CreateIterator() Iterator // создать и вернуть итератор
}

// Определите структуру ConcreteAggregate, которая реализует интерфейс Aggregate.
type ConcreteAggregate struct {
 items []string // полимеризацияобъектхранилищеизсписок элементов
}

// CreateIteratorметодвыполнить,используется длясоздаватьи вернутьсяодин Итератор
func (a *ConcreteAggregate) CreateIterator() Iterator {
 return &ConcreteIterator{items: a.items, index: 0} // возвращатьсяодинновыйиз Итератор Пример
}

func main() {
 // создаватьполимеризацияобъект并добавить вэлемент
 aggregate := &ConcreteAggregate{items: []string{"Item1", "Item2", "Item3"}}

 // использоватьполимеризацияобъектсоздавать Итератор
 iterator := aggregate.CreateIterator()

 // использовать Итератортраверсполимеризацияобъектсерединаизвсе элементы
 for iterator.Next() {
     fmt.Println(iterator.Current())
 }
}

-End-

Автор оригинала|Ван Шуньчи

boy illustration
Что такое подробное объяснение файла WSDL_wsdl
boy illustration
Как запустить большую модель ИИ локально
boy illustration
Подведение итогов десяти самых популярных веб-фреймворков для Go
boy illustration
5 рекомендуемых проектов CMS с открытым исходным кодом на базе .Net Core
boy illustration
Java использует httpclient для отправки запросов HttpPost (отправка формы, загрузка файлов и передача данных Json)
boy illustration
Руководство по развертыванию Nginx в Linux (Centos)
boy illustration
Интервью с Alibaba по Java: можно ли использовать @Transactional и @Async вместе?
boy illustration
Облачный шлюз Spring реализует примеры балансировки нагрузки и проверки входа в систему.
boy illustration
Используйте Nginx для решения междоменных проблем
boy illustration
Произошла ошибка, когда сервер веб-сайта установил соединение с базой данных. WordPress предложил решение проблемы с установкой соединения с базой данных... [Легко понять]
boy illustration
Новый адрес java-библиотеки_16 топовых Java-проектов с открытым исходным кодом, достойных вашего внимания! Обязательно к просмотру новичкам
boy illustration
Лучшие практики Kubernetes для устранения несоответствий часовых поясов внутри контейнеров
boy illustration
Введение в проект удаления водяных знаков из коротких видео на GitHub Douyin_TikTok_Download_API
boy illustration
Весенние аннотации: подробное объяснение @Service!
boy illustration
Пожалуйста, не используйте foreach для пакетной вставки в MyBatis. Для 5000 фрагментов данных потребовалось 14 минут. .
boy illustration
Как создать проект Node.js с помощью npm?
boy illustration
Mybatis-plus использует typeHandler для преобразования объединенных строк String в списки списков.
boy illustration
Не удалось установить программное обеспечение Mitsubishi. Возможно, возникла проблема с реестром.
boy illustration
Разрешение ошибок проекта SpringBoot 3 mybatis-plus: org.apache.ibatis.binding.BindingException: неверный оператор привязки
boy illustration
Более краткая проверка параметров. Для проверки параметров используйте SpringBoot Validation.
boy illustration
Поиграйтесь с интеграцией Spring Boot (платформа запланированных задач Quartz)
boy illustration
Несколько популярных режимов интерфейса API: RESTful, GraphQL, gRPC, WebSocket, Webhook.
boy illustration
Redis: практика публикации (pub) и подписки (sub)
boy illustration
Подробное объяснение пакета Golang Context
boy illustration
Краткое руководство: создайте свое первое приложение .NET Aspire
boy illustration
Краткое обсуждение метода пакетной вставки MyBatis: обработка 100 000 фрагментов данных занимает всего 2 секунды.
boy illustration
[Инструмент] Используйте nvm для управления переключением версий nodejs, это так здорово!
boy illustration
HTML можно преобразовать в word_html для отображения текстовых документов.
boy illustration
Статья Spring Security 6.x для быстрого понимания принципов настройки
boy illustration
Не забудьте изменить имя каждого модуля RUOYI один раз, чтобы избежать мошенничества ~~~