diff --git a/Behavioral/ChainOfResponsibility/chain_of_responsibility.go b/Behavioral/ChainOfResponsibility/chain_of_responsibility.go
index ed59a8d..e2364ed 100644
--- a/Behavioral/ChainOfResponsibility/chain_of_responsibility.go
+++ b/Behavioral/ChainOfResponsibility/chain_of_responsibility.go
@@ -1,52 +1,67 @@
// Package chain_of_responsibility is an example of the Chain Of Responsibility Pattern.
+//
+// In the following example, we are processing requests through a chain of handlers.
+// Each handler either handles the request or passes it to the next handler in the chain.
+//
+// This usage example demonstrates:
+// 1. Creating a chain of handlers (A -> B -> C)
+// 2. Each handler processes messages with a specific value (1, 2, or 3)
+// 3. Requests propagate through the chain until handled
+//
+// The example is meant to show how requests travel through the chain
+// and how each handler decides to process or forward the request.
package chain_of_responsibility
-// Handler provides a handler interface.
+// Handler defines the interface for processing requests in the chain.
type Handler interface {
+ // SendRequest processes a message or forwards it to the next handler.
SendRequest(message int) string
}
-// ConcreteHandlerA implements handler "A".
-type ConcreteHandlerA struct {
+// HandlerA handles messages with value 1.
+type HandlerA struct {
next Handler
}
-// SendRequest implementation.
-func (h *ConcreteHandlerA) SendRequest(message int) (result string) {
+// SendRequest processes message 1 or forwards to the next handler.
+func (h *HandlerA) SendRequest(message int) string {
if message == 1 {
- result = "Im handler 1"
- } else if h.next != nil {
- result = h.next.SendRequest(message)
+ return "Handler A processed message 1"
}
- return
+ if h.next != nil {
+ return h.next.SendRequest(message)
+ }
+ return ""
}
-// ConcreteHandlerB implements handler "B".
-type ConcreteHandlerB struct {
+// HandlerB handles messages with value 2.
+type HandlerB struct {
next Handler
}
-// SendRequest implementation.
-func (h *ConcreteHandlerB) SendRequest(message int) (result string) {
+// SendRequest processes message 2 or forwards to the next handler.
+func (h *HandlerB) SendRequest(message int) string {
if message == 2 {
- result = "Im handler 2"
- } else if h.next != nil {
- result = h.next.SendRequest(message)
+ return "Handler B processed message 2"
+ }
+ if h.next != nil {
+ return h.next.SendRequest(message)
}
- return
+ return ""
}
-// ConcreteHandlerC implements handler "C".
-type ConcreteHandlerC struct {
+// HandlerC handles messages with value 3.
+type HandlerC struct {
next Handler
}
-// SendRequest implementation.
-func (h *ConcreteHandlerC) SendRequest(message int) (result string) {
+// SendRequest processes message 3 or forwards to the next handler.
+func (h *HandlerC) SendRequest(message int) string {
if message == 3 {
- result = "Im handler 3"
- } else if h.next != nil {
- result = h.next.SendRequest(message)
+ return "Handler C processed message 3"
+ }
+ if h.next != nil {
+ return h.next.SendRequest(message)
}
- return
+ return ""
}
diff --git a/Behavioral/Command/command.go b/Behavioral/Command/command.go
index 3f9f5a3..cfff6be 100644
--- a/Behavioral/Command/command.go
+++ b/Behavioral/Command/command.go
@@ -1,4 +1,17 @@
// Package command is an example of the Command Pattern.
+//
+// In the following example, we are implementing a simple toggle system.
+// Commands encapsulate requests as objects, allowing parameterization
+// and queueing of operations.
+//
+// This usage example demonstrates:
+// 1. Command interface for executing operations
+// 2. Concrete commands (ToggleOn, ToggleOff) that call receiver methods
+// 3. Receiver that performs the actual work
+// 4. Invoker that stores and executes commands
+//
+// The example is meant to show how commands decouple the sender (Invoker)
+// from the receiver, and how multiple commands can be queued and executed.
package command
// Command provides a command interface.
@@ -11,7 +24,7 @@ type ToggleOnCommand struct {
receiver *Receiver
}
-// Execute command.
+// Execute calls ToggleOn on the receiver.
func (c *ToggleOnCommand) Execute() string {
return c.receiver.ToggleOn()
}
@@ -21,43 +34,44 @@ type ToggleOffCommand struct {
receiver *Receiver
}
-// Execute command.
+// Execute calls ToggleOff on the receiver.
func (c *ToggleOffCommand) Execute() string {
return c.receiver.ToggleOff()
}
-// Receiver implementation.
+// Receiver performs the actual work when commands are executed.
type Receiver struct {
}
-// ToggleOn implementation.
+// ToggleOn returns string indicating device turned on.
func (r *Receiver) ToggleOn() string {
return "Toggle On"
}
-// ToggleOff implementation.
+// ToggleOff returns string indicating device turned off.
func (r *Receiver) ToggleOff() string {
return "Toggle Off"
}
-// Invoker implementation.
+// Invoker stores and executes commands.
+// It acts as the sender that triggers command execution.
type Invoker struct {
commands []Command
}
-// StoreCommand adds command.
+// StoreCommand adds a command to the execution queue.
func (i *Invoker) StoreCommand(command Command) {
i.commands = append(i.commands, command)
}
-// UnStoreCommand removes command.
+// UnStoreCommand removes the last command from the queue.
func (i *Invoker) UnStoreCommand() {
if len(i.commands) != 0 {
i.commands = i.commands[:len(i.commands)-1]
}
}
-// Execute all commands.
+// Execute runs all stored commands in order.
func (i *Invoker) Execute() string {
var result string
for _, command := range i.commands {
diff --git a/Behavioral/Iterator/iterator.go b/Behavioral/Iterator/iterator.go
index 7ffb0ff..62d5402 100644
--- a/Behavioral/Iterator/iterator.go
+++ b/Behavioral/Iterator/iterator.go
@@ -1,7 +1,20 @@
// Package iterator is an example of the Iterator Pattern.
+//
+// In the following example, we are implementing a book shelf that can be
+// traversed with an iterator. The iterator provides a way to access elements
+// of a collection sequentially without exposing the underlying structure.
+//
+// This usage example demonstrates:
+// 1. Iterator interface with navigation methods (Next, Prev, Reset, End)
+// 2. Aggregate interface for creating iterators
+// 3. Concrete collection (BookShelf) that stores books
+// 4. Concrete iterator (BookIterator) that traverses the collection
+//
+// The example is meant to show how clients can iterate over a collection
+// without knowing its internal representation.
package iterator
-// Iterator provides a iterator interface.
+// Iterator provides an interface for traversing a collection.
type Iterator interface {
Index() int
Value() interface{}
@@ -12,37 +25,37 @@ type Iterator interface {
End()
}
-// Aggregate provides a collection interface.
+// Aggregate provides an interface for creating an iterator.
type Aggregate interface {
Iterator() Iterator
}
-// BookIterator implements the Iterator interface.
+// BookIterator implements the Iterator interface for BookShelf.
type BookIterator struct {
shelf *BookShelf
- index int
- internal int
+ index int // current position for external access
+ internal int // internal position for navigation
}
-// Index returns current index
+// Index returns the current position in the collection.
func (i *BookIterator) Index() int {
return i.index
}
-// Value returns current value
+// Value returns the current book at the iterator position.
func (i *BookIterator) Value() interface{} {
+ if i.index < 0 || i.index >= len(i.shelf.Books) {
+ return nil
+ }
return i.shelf.Books[i.index]
}
-// Has implementation.
+// Has checks if the current internal position is valid.
func (i *BookIterator) Has() bool {
- if i.internal < 0 || i.internal >= len(i.shelf.Books) {
- return false
- }
- return true
+ return i.internal >= 0 && i.internal < len(i.shelf.Books)
}
-// Next goes to the next item.
+// Next moves the iterator forward by one position.
func (i *BookIterator) Next() {
i.internal++
if i.Has() {
@@ -50,7 +63,7 @@ func (i *BookIterator) Next() {
}
}
-// Prev goes to the previous item.
+// Prev moves the iterator backward by one position.
func (i *BookIterator) Prev() {
i.internal--
if i.Has() {
@@ -58,34 +71,34 @@ func (i *BookIterator) Prev() {
}
}
-// Reset resets iterator.
+// Reset positions the iterator at the beginning.
func (i *BookIterator) Reset() {
i.index = 0
i.internal = 0
}
-// End goes to the last item.
+// End positions the iterator at the last element.
func (i *BookIterator) End() {
i.index = len(i.shelf.Books) - 1
i.internal = i.index
}
-// BookShelf implements the Aggregate interface.
+// BookShelf implements the Aggregate interface and stores books.
type BookShelf struct {
Books []*Book
}
-// Iterator creates and returns the iterator over the collection.
+// Iterator creates a new iterator for the book shelf.
func (b *BookShelf) Iterator() Iterator {
return &BookIterator{shelf: b}
}
-// Add adds an item to the collection.
+// Add appends a book to the collection.
func (b *BookShelf) Add(book *Book) {
b.Books = append(b.Books, book)
}
-// Book implements a item of the collection.
+// Book represents a single book in the collection.
type Book struct {
Name string
}
diff --git a/Behavioral/Mediator/mediator.go b/Behavioral/Mediator/mediator.go
index af6621b..86fe014 100644
--- a/Behavioral/Mediator/mediator.go
+++ b/Behavioral/Mediator/mediator.go
@@ -1,123 +1,140 @@
// Package mediator is an example of the Mediator Pattern.
+//
+// In the following example, we are implementing a production chain:
+// Farmer grows tomatoes, Cannery makes ketchup, Shop sells it.
+// The mediator coordinates communication between all colleagues,
+// reducing direct dependencies between them.
+//
+// This usage example demonstrates:
+// 1. Mediator interface for communication between colleagues
+// 2. Concrete mediator that coordinates Farmer, Cannery, and Shop
+// 3. Colleagues that communicate only through the mediator
+// 4. Money transfers and product transformations along the chain
+//
+// The example is meant to show how the mediator centralizes complex
+// communication logic and keeps colleagues loosely coupled.
package mediator
-// Mediator provides a mediator interface.
+// Mediator defines the interface for communication between colleagues.
type Mediator interface {
Notify(msg string)
}
-// Тип ConcreteMediator, реализует посредника
+// ConcreteMediator implements the mediator and coordinates all colleagues.
type ConcreteMediator struct {
*Farmer
*Cannery
*Shop
}
-// Notify implementation.
+// Notify handles messages from colleagues and coordinates the workflow.
func (m *ConcreteMediator) Notify(msg string) {
- if msg == "Farmer: Tomato complete..." {
+ switch msg {
+ case "Farmer: Tomato complete...":
+ // Farmer gets paid, Cannery starts production
m.Cannery.AddMoney(-15000.00)
m.Farmer.AddMoney(15000.00)
m.Cannery.MakeKetchup(m.Farmer.GetTomato())
- } else if msg == "Cannery: Ketchup complete..." {
+ case "Cannery: Ketchup complete...":
+ // Cannery gets paid, Shop starts selling
m.Shop.AddMoney(-30000.00)
m.Cannery.AddMoney(30000.00)
m.Shop.SellKetchup(m.Cannery.GetKetchup())
}
}
-// СonnectСolleagues connects all colleagues.
-func СonnectСolleagues(farmer *Farmer, cannery *Cannery, shop *Shop) {
+// ConnectColleagues creates a mediator and connects all colleagues together.
+func ConnectColleagues(farmer *Farmer, cannery *Cannery, shop *Shop) {
mediator := &ConcreteMediator{
Farmer: farmer,
Cannery: cannery,
Shop: shop,
}
- mediator.Farmer.SetMediator(mediator)
- mediator.Cannery.SetMediator(mediator)
- mediator.Shop.SetMediator(mediator)
+ farmer.SetMediator(mediator)
+ cannery.SetMediator(mediator)
+ shop.SetMediator(mediator)
}
-// Farmer implements a Farmer colleague
+// Farmer represents a colleague that grows tomatoes.
type Farmer struct {
mediator Mediator
tomato int
money float64
}
-// SetMediator sets mediator.
+// SetMediator assigns a mediator to the farmer.
func (f *Farmer) SetMediator(mediator Mediator) {
f.mediator = mediator
}
-// AddMoney adds money.
+// AddMoney changes the farmer's balance.
func (f *Farmer) AddMoney(m float64) {
f.money += m
}
-// GrowTomato implementation.
+// GrowTomato starts the production chain by growing tomatoes.
func (f *Farmer) GrowTomato(tomato int) {
f.tomato = tomato
f.money -= 7500.00
f.mediator.Notify("Farmer: Tomato complete...")
}
-// GetTomato returns tomatos.
+// GetTomato returns the amount of grown tomatoes.
func (f *Farmer) GetTomato() int {
return f.tomato
}
-// Cannery implements a Cannery colleague.
+// Cannery represents a colleague that processes tomatoes into ketchup.
type Cannery struct {
mediator Mediator
ketchup int
money float64
}
-// SetMediator sets mediator.
+// SetMediator assigns a mediator to the cannery.
func (c *Cannery) SetMediator(mediator Mediator) {
c.mediator = mediator
}
-// AddMoney adds money.
+// AddMoney changes the cannery's balance.
func (c *Cannery) AddMoney(m float64) {
c.money += m
}
-// MakeKetchup implementation.
+// MakeKetchup processes tomatoes into ketchup.
func (c *Cannery) MakeKetchup(tomato int) {
c.ketchup = tomato
c.mediator.Notify("Cannery: Ketchup complete...")
}
-// GetKetchup returns ketchup.
+// GetKetchup returns the amount of produced ketchup.
func (c *Cannery) GetKetchup() int {
return c.ketchup
}
-// Shop implements a Shop colleague.
+// Shop represents a colleague that sells ketchup to customers.
type Shop struct {
mediator Mediator
money float64
}
-// SetMediator sets mediator.
+// SetMediator assigns a mediator to the shop.
func (s *Shop) SetMediator(mediator Mediator) {
s.mediator = mediator
}
-// AddMoney adds money.
+// AddMoney changes the shop's balance.
func (s *Shop) AddMoney(m float64) {
s.money += m
}
-// SellKetchup converts ketchup to money.
+// SellKetchup converts ketchup inventory into money.
func (s *Shop) SellKetchup(ketchup int) {
s.money = float64(ketchup) * 54.75
}
-// GetMoney returns money.
+// GetMoney returns the shop's current balance.
func (s *Shop) GetMoney() float64 {
return s.money
}
diff --git a/Behavioral/Memento/memento.go b/Behavioral/Memento/memento.go
index 3489630..ba9805e 100644
--- a/Behavioral/Memento/memento.go
+++ b/Behavioral/Memento/memento.go
@@ -1,32 +1,46 @@
// Package memento is an example of the Memento Pattern.
+//
+// In the following example, we are implementing an undo mechanism.
+// Originator creates and restores its state, Memento stores snapshots,
+// and Caretaker manages the saved states without examining them.
+//
+// This usage example demonstrates:
+// 1. Originator that can save and restore its state
+// 2. Memento that stores state snapshots (immutable)
+// 3. Caretaker that holds mementos without accessing their contents
+//
+// The example is meant to show how state can be captured and restored
+// without breaking encapsulation.
package memento
-// Originator implements a state master.
+// Originator represents an object whose state needs to be saved and restored.
type Originator struct {
State string
}
-// CreateMemento returns state storage.
+// CreateMemento saves the current state into a memento.
func (o *Originator) CreateMemento() *Memento {
return &Memento{state: o.State}
}
-// SetMemento sets old state.
+// SetMemento restores a previously saved state from a memento.
func (o *Originator) SetMemento(memento *Memento) {
o.State = memento.GetState()
}
-// Memento implements storage for the state of Originator
+// Memento stores a snapshot of the Originator's state.
+// It provides restricted access - only Originator can read the state.
type Memento struct {
state string
}
-// GetState returns state.
+// GetState returns the stored state (intended for Originator use only).
func (m *Memento) GetState() string {
return m.state
}
-// Caretaker keeps Memento until it is needed by Originator.
+// Caretaker manages mementos without modifying or inspecting them.
+// It's responsible for safekeeping and returning mementos to Originator.
type Caretaker struct {
Memento *Memento
}
diff --git a/Behavioral/Observer/observer.go b/Behavioral/Observer/observer.go
index 2dc620a..f870615 100644
--- a/Behavioral/Observer/observer.go
+++ b/Behavioral/Observer/observer.go
@@ -1,16 +1,33 @@
// Package observer is an example of the Observer Pattern.
-// Push model.
+// Push model - publisher sends state to all observers.
+//
+// In the following example, we are implementing a notification system.
+// Publisher maintains a list of observers and notifies them of state changes.
+// Observers automatically update when publisher's state changes.
+//
+// This usage example demonstrates:
+// 1. Publisher interface for attaching observers and sending notifications
+// 2. Observer interface for receiving updates
+// 3. Concrete publisher that tracks state and notifies all observers
+// 4. Concrete observers that update their state when notified
+//
+// The example uses the push model where publisher sends the state
+// directly to all observers during notification.
package observer
-// Publisher interface.
+// Publisher defines the interface for managing observers and sending updates.
type Publisher interface {
+ // Attach adds a new observer to the notification list.
Attach(observer Observer)
+ // SetState changes the publisher's internal state.
SetState(state string)
+ // Notify sends the current state to all attached observers.
Notify()
}
-// Observer provides a subscriber interface.
+// Observer defines the interface for receiving updates from publisher.
type Observer interface {
+ // Update is called by publisher when state changes.
Update(state string)
}
@@ -20,26 +37,26 @@ type ConcretePublisher struct {
state string
}
-// NewPublisher is the Publisher constructor.
+// NewPublisher creates and returns a new ConcretePublisher.
func NewPublisher() Publisher {
return &ConcretePublisher{}
}
-// Attach a Observer
-func (s *ConcretePublisher) Attach(observer Observer) {
- s.observers = append(s.observers, observer)
+// Attach adds a new observer to the notification list.
+func (p *ConcretePublisher) Attach(observer Observer) {
+ p.observers = append(p.observers, observer)
}
-// SetState sets new state
-func (s *ConcretePublisher) SetState(state string) {
- s.state = state
+// SetState updates the publisher's internal state.
+func (p *ConcretePublisher) SetState(state string) {
+ p.state = state
}
-// Notify sends notifications to subscribers.
-// Push model.
-func (s *ConcretePublisher) Notify() {
- for _, observer := range s.observers {
- observer.Update(s.state)
+// Notify sends the current state to all attached observers.
+// Push model - publisher pushes state to observers.
+func (p *ConcretePublisher) Notify() {
+ for _, observer := range p.observers {
+ observer.Update(p.state)
}
}
@@ -48,7 +65,7 @@ type ConcreteObserver struct {
state string
}
-// Update set new state
-func (s *ConcreteObserver) Update(state string) {
- s.state = state
+// Update sets the observer's state to match the publisher's state.
+func (o *ConcreteObserver) Update(state string) {
+ o.state = state
}
diff --git a/Behavioral/README.md b/Behavioral/README.md
index 627767c..ded6cfe 100644
--- a/Behavioral/README.md
+++ b/Behavioral/README.md
@@ -1,34 +1,33 @@
-
## Поведенческие паттерны (Behavioral)
Поведенческие паттерны делятся на два типа:
1. Паттерны уровня класса
-2. Паттерны уровня объекта.
+2. Паттерны уровня объекта
-Паттерны уровня класса описывают взаимодействия между классами и их подклассами. Такие отношения выражаются путем наследования и реализации классов. Тут базовый класс определяет интерфейс, а подклассы - реализацию.
+Паттерны уровня класса описывают взаимодействие между классами и их подклассами. Такие отношения выражаются через наследование и реализацию интерфейсов. Базовый класс определяет интерфейс, а подклассы предоставляют конкретную реализацию.
-Паттерны уровня объекта описывают взаимодействия между объектами. Такие отношения выражаются связями - ассоциацией, агрегацией и композицией. Тут структуры строятся путем объединения объектов некоторых классов.
+Паттерны уровня объекта описывают взаимодействие между объектами. Такие отношения выражаются через связи: ассоциацию, агрегацию и композицию. Структуры строятся путем объединения объектов различных классов.
-Ассоциация - отношение, когда объекты двух классов могут ссылаться один на другой. Например, свойство класса содержит экземпляр другого класса.
+**Ассоциация** - отношение, при котором объекты двух классов могут ссылаться друг на друга. Например, свойство одного класса содержит экземпляр другого класса.
-Агрегация – частная форма ассоциации. Агрегация применяется, когда один объект должен быть контейнером для других объектов и время существования этих объектов никак не зависит от времени существования объекта контейнера. Вообщем, если контейнер будет уничтожен, то входящие в него объекты не пострадают. Например, мы создали объект, а потом передали его в объект контейнер, каким-либо образом, можно в метод объекта контейнера передать или присвоить сразу свойству контейнера извне. Значит при удалении контейнера мы ни как не затронем наш созданный объект, который может взаимодействовать и с другими контейнерами.
+**Агрегация** - частная форма ассоциации. Агрегация применяется, когда один объект выступает контейнером для других объектов, но время жизни этих объектов не зависит от времени жизни контейнера. Если контейнер будет уничтожен, входящие в него объекты продолжают существовать. Например, мы создаем объект и передаем его в контейнер через метод или присваиваем свойству. При удалении контейнера объект остается доступным и может использоваться другими контейнерами.
-Композиция – Тоже самое, что и агрегация, но составные объекты не могут существовать отдельно от объекта контейнера и если контейнер будет уничтожен, то всё его содержимое будет уничтожено тоже. Например, мы создали объект в методе объекта контейнера и присвоили его свойству объекта контейнера. Из вне, о нашем созданном объекте никто не знает, значит, при удалении контейнера, созданный объект убудет удален так же, т.к. на него нет ссылки извне.
+**Композиция** - более строгая форма агрегации. Составные объекты не могут существовать отдельно от контейнера. Если контейнер уничтожается, всё его содержимое уничтожается тоже. Например, объект создается внутри метода контейнера и присваивается его свойству. Извне об этом объекте никто не знает, поэтому при удалении контейнера объект становится недоступным и удаляется сборщиком мусора.
К паттернам уровня класса относится только «Шаблонный метод».
-Поведенческие паттерны описывают взаимодействие объектов и классов между собой и пытаются добиться наименьшей степени связанности компонентов системы друг с другом делая систему более гибкой.
-
-* [Цепочка ответственности (Chain Of Responsibility)](ChainOfResponsibility)
-* [Команда (Command)](Command)
-* [Итератор (Iterator)](Iterator)
-* [Посредник (Mediator)](Mediator)
-* [Хранитель (Memento)](Memento)
-* [Наблюдатель (Observer)](Observer)
-* [Состояние (State)](State)
-* [Стратегия (Strategy)](Strategy)
-* [Шаблонный метод (Template Method)](TemplateMethod)
-* [Посетитель (Visitor)](Visitor)
+Поведенческие паттерны описывают взаимодействие объектов и классов между собой, стремясь к минимальной связанности компонентов системы. Это делает систему более гибкой и легкой для расширения.
+
+* [Цепочка ответственности (Chain of Responsibility)](ChainOfResponsibility)
+* [Команда (Command)](Command)
+* [Итератор (Iterator)](Iterator)
+* [Посредник (Mediator)](Mediator)
+* [Хранитель (Memento)](Memento)
+* [Наблюдатель (Observer)](Observer)
+* [Состояние (State)](State)
+* [Стратегия (Strategy)](Strategy)
+* [Шаблонный метод (Template Method)](TemplateMethod)
+* [Посетитель (Visitor)](Visitor)
## -~- THE END -~-
\ No newline at end of file
diff --git a/Behavioral/State/state.go b/Behavioral/State/state.go
index 298cc8a..7b77c85 100644
--- a/Behavioral/State/state.go
+++ b/Behavioral/State/state.go
@@ -1,45 +1,58 @@
// Package state is an example of the State Pattern.
+//
+// In the following example, we are implementing a mobile phone alert system.
+// The phone can be in different alert states (vibration, song) and its behavior
+// changes depending on the current state.
+//
+// This usage example demonstrates:
+// 1. State interface defining behavior common to all states
+// 2. Context (MobileAlert) that maintains a reference to current state
+// 3. Concrete states (Vibration, Song) with specific implementations
+// 4. Dynamic state changes at runtime
+//
+// The example is meant to show how an object can alter its behavior
+// when its internal state changes.
package state
-// MobileAlertStater provides a common interface for various states.
+// MobileAlertStater defines the interface for all alert states.
type MobileAlertStater interface {
Alert() string
}
-// MobileAlert implements an alert depending on its state.
+// MobileAlert represents the context that changes behavior based on state.
type MobileAlert struct {
state MobileAlertStater
}
-// Alert returns a alert string
+// Alert delegates the alert behavior to the current state.
func (a *MobileAlert) Alert() string {
return a.state.Alert()
}
-// SetState changes state
+// SetState changes the current alert state at runtime.
func (a *MobileAlert) SetState(state MobileAlertStater) {
a.state = state
}
-// NewMobileAlert is the MobileAlert constructor.
+// NewMobileAlert creates a new alert with default vibration state.
func NewMobileAlert() *MobileAlert {
return &MobileAlert{state: &MobileAlertVibration{}}
}
-// MobileAlertVibration implements vibration alert
+// MobileAlertVibration implements vibration alert behavior.
type MobileAlertVibration struct {
}
-// Alert returns a alert string
-func (a *MobileAlertVibration) Alert() string {
+// Alert returns vibration notification string.
+func (v *MobileAlertVibration) Alert() string {
return "Vrrr... Brrr... Vrrr..."
}
-// MobileAlertSong implements beep alert
+// MobileAlertSong implements song alert behavior.
type MobileAlertSong struct {
}
-// Alert returns a alert string
-func (a *MobileAlertSong) Alert() string {
+// Alert returns song notification string.
+func (s *MobileAlertSong) Alert() string {
return "Белые розы, Белые розы. Беззащитны шипы..."
}
diff --git a/Behavioral/Strategy/strategy.go b/Behavioral/Strategy/strategy.go
index b6b7a1a..0157ba1 100644
--- a/Behavioral/Strategy/strategy.go
+++ b/Behavioral/Strategy/strategy.go
@@ -1,64 +1,90 @@
-// Package strategy is an example of the Strategy Pattern.
+// Package strategy provides implementations of the Strategy pattern
+// for sorting algorithms.
+//
+// In the following example, we are implementing different sorting algorithms
+// that can be interchanged at runtime. The Context delegates sorting to the
+// currently selected strategy.
+//
+// This usage example demonstrates:
+// 1. Strategy interface (Sorter) that all algorithms implement
+// 2. Concrete strategies (BubbleSort, InsertionSort) with different algorithms
+// 3. Context that maintains a reference to current strategy
+// 4. Dynamic strategy switching at runtime
+//
+// The example is meant to show how algorithms can be selected and changed
+// without modifying the client code.
package strategy
-// StrategySort provides an interface for sort algorithms.
-type StrategySort interface {
- Sort([]int)
+// Sorter defines the interface for sorting algorithms.
+//
+// Example:
+//
+// sorter := &BubbleSort{}
+// data := []int{3, 1, 4, 1, 5}
+// sorter.Sort(data)
+type Sorter interface {
+ Sort(data []int)
}
-// BubbleSort implements bubble sort algorithm.
-type BubbleSort struct {
-}
+// BubbleSort implements the bubble sort algorithm.
+// Time complexity: O(n²) average and worst case, O(n) best case.
+type BubbleSort struct{}
-// Sort sorts data.
-func (s *BubbleSort) Sort(a []int) {
- size := len(a)
- if size < 2 {
+// Sort performs an in-place bubble sort on the input slice.
+func (b *BubbleSort) Sort(data []int) {
+ if len(data) < 2 {
return
}
- for i := 0; i < size; i++ {
- for j := size - 1; j >= i+1; j-- {
- if a[j] < a[j-1] {
- a[j], a[j-1] = a[j-1], a[j]
+
+ swapped := true
+ for swapped {
+ swapped = false
+ for i := 0; i < len(data)-1; i++ {
+ if data[i] > data[i+1] {
+ data[i], data[i+1] = data[i+1], data[i]
+ swapped = true
}
}
}
}
-// InsertionSort implements insertion sort algorithm.
-type InsertionSort struct {
-}
+// InsertionSort implements the insertion sort algorithm.
+// Time complexity: O(n²) average and worst case, O(n) best case.
+type InsertionSort struct{}
-// Sort sorts data.
-func (s *InsertionSort) Sort(a []int) {
- size := len(a)
- if size < 2 {
+// Sort performs an in-place insertion sort on the input slice.
+func (i *InsertionSort) Sort(data []int) {
+ if len(data) < 2 {
return
}
- for i := 1; i < size; i++ {
- var j int
- var buff = a[i]
- for j = i - 1; j >= 0; j-- {
- if a[j] < buff {
- break
- }
- a[j+1] = a[j]
+
+ for i := 1; i < len(data); i++ {
+ curr := data[i]
+ j := i - 1
+ for j >= 0 && data[j] > curr {
+ data[j+1] = data[j]
+ j--
}
- a[j+1] = buff
+ data[j+1] = curr
}
}
-// Context provides a context for execution of a strategy.
+// Context holds a sorting strategy and delegates sorting to it.
+// It allows switching between different algorithms at runtime.
type Context struct {
- strategy StrategySort
+ strategy Sorter
}
-// Algorithm replaces strategies.
-func (c *Context) Algorithm(a StrategySort) {
- c.strategy = a
+// SetStrategy replaces the current sorting strategy.
+func (c *Context) SetStrategy(s Sorter) {
+ c.strategy = s
}
-// Sort sorts data according to the chosen strategy.
-func (c *Context) Sort(s []int) {
- c.strategy.Sort(s)
+// Sort sorts data using the current strategy.
+// Panics if no strategy is set.
+func (c *Context) Sort(data []int) {
+ if c.strategy == nil {
+ panic("strategy: no strategy set")
+ }
+ c.strategy.Sort(data)
}
diff --git a/Behavioral/TemplateMethod/template_method.go b/Behavioral/TemplateMethod/template_method.go
index fd0428a..2387636 100644
--- a/Behavioral/TemplateMethod/template_method.go
+++ b/Behavioral/TemplateMethod/template_method.go
@@ -1,53 +1,66 @@
// Package template_method is an example of the Template Method Pattern.
+//
+// In the following example, we are implementing a text formatter that wraps
+// strings in different styles of quotation marks. The template method defines
+// the skeleton of the algorithm (open + string + close), while subclasses
+// provide the specific implementation for each quote style.
+//
+// This usage example demonstrates:
+// 1. Template method (Quotes) that defines the algorithm structure
+// 2. Interface for primitive operations (Open, Close)
+// 3. Concrete implementations for different quote styles (French, German)
+//
// In fact, this pattern is based on Abstract Class and Polymorphism.
-// But there’s nothing like that in Go, so the composition will be applied.
+// But there's nothing like that in Go, so composition is applied instead.
package template_method
-// QuotesInterface provides an interface for setting different quotes.
+// QuotesInterface defines the primitive operations that concrete types must implement.
+// These operations are used by the template method to build the final result.
type QuotesInterface interface {
Open() string
Close() string
}
-// Quotes implements a Template Method.
+// Quotes implements the template method using composition.
type Quotes struct {
QuotesInterface
}
-// Quotes is the Template Method.
+// Quotes is the template method that defines the algorithm skeleton.
+// It calls primitive operations implemented by concrete types.
func (q *Quotes) Quotes(str string) string {
return q.Open() + str + q.Close()
}
-// NewQuotes is the Quotes constructor.
+// NewQuotes creates a new Quotes with the provided quote style implementation.
func NewQuotes(qt QuotesInterface) *Quotes {
return &Quotes{qt}
}
-// FrenchQuotes implements wrapping the string in French quotes.
+// FrenchQuotes implements string wrapping in French quotes.
type FrenchQuotes struct {
}
-// Open sets opening quotes.
-func (q *FrenchQuotes) Open() string {
+// Open returns the French opening quotation mark.
+func (f *FrenchQuotes) Open() string {
return "«"
}
-// Close sets closing quotes.
-func (q *FrenchQuotes) Close() string {
+// Close returns the French closing quotation mark.
+func (f *FrenchQuotes) Close() string {
return "»"
}
-// GermanQuotes implements wrapping the string in German quotes.
+// GermanQuotes implements string wrapping in German quotes.
type GermanQuotes struct {
}
-// Open sets opening quotes.
-func (q *GermanQuotes) Open() string {
+// Open returns the German opening quotation mark.
+func (g *GermanQuotes) Open() string {
return "„"
}
-// Close sets closing quotes.
-func (q *GermanQuotes) Close() string {
+// Close returns the German closing quotation mark.
+func (g *GermanQuotes) Close() string {
return "“"
}
diff --git a/Behavioral/Visitor/visitor.go b/Behavioral/Visitor/visitor.go
index 460f55a..0087e29 100644
--- a/Behavioral/Visitor/visitor.go
+++ b/Behavioral/Visitor/visitor.go
@@ -1,48 +1,62 @@
// Package visitor is an example of the Visitor Pattern.
+//
+// In the following example, we are implementing a city exploration system.
+// A person (visitor) can visit different places (sushi bar, pizzeria, burger bar)
+// and perform place-specific actions without modifying the places themselves.
+//
+// This usage example demonstrates:
+// 1. Visitor interface with methods for each place type
+// 2. Place interface that accepts visitors
+// 3. Concrete visitor (People) that implements operations for all places
+// 4. Concrete places with their specific behaviors
+// 5. Collection (City) that can be visited as a whole
+//
+// The example is meant to show how to add new operations to existing
+// object structures without modifying them.
package visitor
-// Visitor provides a visitor interface.
+// Visitor defines operations to be performed on different types of places.
type Visitor interface {
VisitSushiBar(p *SushiBar) string
VisitPizzeria(p *Pizzeria) string
VisitBurgerBar(p *BurgerBar) string
}
-// Place provides an interface for place that the visitor should visit.
+// Place defines an interface for elements that can be visited.
type Place interface {
Accept(v Visitor) string
}
-// People implements the Visitor interface.
+// People implements the Visitor interface for a person exploring places.
type People struct {
}
-// VisitSushiBar implements visit to SushiBar.
+// VisitSushiBar implements visiting a sushi bar.
func (v *People) VisitSushiBar(p *SushiBar) string {
return p.BuySushi()
}
-// VisitPizzeria implements visit to Pizzeria.
+// VisitPizzeria implements visiting a pizzeria.
func (v *People) VisitPizzeria(p *Pizzeria) string {
return p.BuyPizza()
}
-// VisitBurgerBar implements visit to BurgerBar.
+// VisitBurgerBar implements visiting a burger bar.
func (v *People) VisitBurgerBar(p *BurgerBar) string {
return p.BuyBurger()
}
-// City implements a collection of places to visit.
+// City represents a collection of places that can be visited.
type City struct {
places []Place
}
-// Add appends Place to the collection.
+// Add appends a new place to the city.
func (c *City) Add(p Place) {
c.places = append(c.places, p)
}
-// Accept implements a visit to all places in the city.
+// Accept makes the visitor visit all places in the city.
func (c *City) Accept(v Visitor) string {
var result string
for _, p := range c.places {
@@ -51,44 +65,44 @@ func (c *City) Accept(v Visitor) string {
return result
}
-// SushiBar implements the Place interface.
+// SushiBar represents a place that sells sushi.
type SushiBar struct {
}
-// Accept implementation.
+// Accept allows a visitor to visit the sushi bar.
func (s *SushiBar) Accept(v Visitor) string {
return v.VisitSushiBar(s)
}
-// BuySushi implementation.
+// BuySushi returns the sushi bar's specific operation.
func (s *SushiBar) BuySushi() string {
return "Buy sushi..."
}
-// Pizzeria implements the Place interface.
+// Pizzeria represents a place that sells pizza.
type Pizzeria struct {
}
-// Accept implementation.
+// Accept allows a visitor to visit the pizzeria.
func (p *Pizzeria) Accept(v Visitor) string {
return v.VisitPizzeria(p)
}
-// BuyPizza implementation.
+// BuyPizza returns the pizzeria's specific operation.
func (p *Pizzeria) BuyPizza() string {
return "Buy pizza..."
}
-// BurgerBar implements the Place interface.
+// BurgerBar represents a place that sells burgers.
type BurgerBar struct {
}
-// Accept implementation.
+// Accept allows a visitor to visit the burger bar.
func (b *BurgerBar) Accept(v Visitor) string {
return v.VisitBurgerBar(b)
}
-// BuyBurger implementation.
+// BuyBurger returns the burger bar's specific operation.
func (b *BurgerBar) BuyBurger() string {
return "Buy burger..."
}
diff --git a/Creational/AbstractFactory/abstract_factory.go b/Creational/AbstractFactory/abstract_factory.go
index 7e0cfc8..37d4f0c 100644
--- a/Creational/AbstractFactory/abstract_factory.go
+++ b/Creational/AbstractFactory/abstract_factory.go
@@ -1,70 +1,88 @@
// Package abstract_factory is an example of the Abstract Factory Pattern.
+//
+// In the following example, we are implementing a drink production system.
+// CocaColaFactory creates a family of related products: CocaColaWater and
+// CocaColaBottle. The factory ensures that products from the same family
+// work together correctly.
+//
+// This usage example demonstrates:
+// 1. Abstract factory interface for creating product families
+// 2. Abstract product interfaces (Water, Bottle) that products must implement
+// 3. Concrete factory (CocaColaFactory) that creates specific products
+// 4. Concrete products (CocaColaWater, CocaColaBottle) that work together
+// 5. Interaction between products (bottle receives water)
+//
+// The example is meant to show how to create families of related objects
+// without specifying their concrete classes.
package abstract_factory
-// AbstractFactory provides an interface for creating families of related objects.
+// AbstractFactory defines an interface for creating families of related products.
type AbstractFactory interface {
CreateWater(volume float64) AbstractWater
CreateBottle(volume float64) AbstractBottle
}
-// AbstractWater provides a water interface.
+// AbstractWater defines the interface for water/drink products.
type AbstractWater interface {
GetVolume() float64
}
-// AbstractBottle provides a bottle interface.
+// AbstractBottle defines the interface for bottle products.
type AbstractBottle interface {
- PourWater(water AbstractWater) // Bottle interacts with a water.
+ PourWater(water AbstractWater) // Bottle interacts with water
GetBottleVolume() float64
GetWaterVolume() float64
}
-// CocaColaFactory implements AbstractFactory interface.
+// CocaColaFactory implements AbstractFactory for Coca-Cola products.
type CocaColaFactory struct {
}
-// NewCocaColaFactory is the CocaColaFactory constructor.
+// NewCocaColaFactory creates a new Coca-Cola factory.
func NewCocaColaFactory() AbstractFactory {
return &CocaColaFactory{}
}
-// CreateWater implementation.
+// CreateWater creates a Coca-Cola water product.
func (f *CocaColaFactory) CreateWater(volume float64) AbstractWater {
return &CocaColaWater{volume: volume}
}
-// CreateBottle implementation.
+// CreateBottle creates a Coca-Cola bottle product.
func (f *CocaColaFactory) CreateBottle(volume float64) AbstractBottle {
return &CocaColaBottle{volume: volume}
}
-// CocaColaWater implements AbstractWater.
+// CocaColaWater implements AbstractWater for Coca-Cola.
type CocaColaWater struct {
- volume float64 // Volume of drink.
+ volume float64
}
-// GetVolume returns volume of drink.
+// GetVolume returns the volume of water in the container.
func (w *CocaColaWater) GetVolume() float64 {
return w.volume
}
-// CocaColaBottle implements AbstractBottle.
+// CocaColaBottle implements AbstractBottle for Coca-Cola.
type CocaColaBottle struct {
- water AbstractWater // Bottle must contain a drink.
- volume float64 // Volume of bottle.
+ water AbstractWater // Current water in the bottle
+ volume float64 // Maximum bottle capacity
}
-// PourWater pours water into a bottle.
+// PourWater pours water into the bottle.
func (b *CocaColaBottle) PourWater(water AbstractWater) {
b.water = water
}
-// GetBottleVolume returns volume of bottle.
+// GetBottleVolume returns the bottle's capacity.
func (b *CocaColaBottle) GetBottleVolume() float64 {
return b.volume
}
-// GetWaterVolume returns volume of water.
+// GetWaterVolume returns the volume of water currently in the bottle.
func (b *CocaColaBottle) GetWaterVolume() float64 {
+ if b.water == nil {
+ return 0
+ }
return b.water.GetVolume()
}
diff --git a/Creational/Builder/builder.go b/Creational/Builder/builder.go
index 59f4302..62c1c77 100644
--- a/Creational/Builder/builder.go
+++ b/Creational/Builder/builder.go
@@ -1,51 +1,67 @@
// Package builder is an example of the Builder Pattern.
+//
+// In the following example, we are implementing a document builder.
+// The Director defines the construction steps, while the ConcreteBuilder
+// implements how to build each part. This separates the construction
+// process from the representation.
+//
+// This usage example demonstrates:
+// 1. Builder interface defining steps to build a product
+// 2. Director that controls the construction process
+// 3. ConcreteBuilder that implements the building steps
+// 4. Product that is the final result of construction
+//
+// The example is meant to show how to construct complex objects step by step
+// and create different representations using the same construction process.
package builder
-// Builder provides a builder interface.
+// Builder defines the interface for creating parts of a product.
type Builder interface {
MakeHeader(str string)
MakeBody(str string)
MakeFooter(str string)
}
-// Director implements a manager
+// Director orchestrates the construction process.
+// It defines the order in which building steps are executed.
type Director struct {
builder Builder
}
-// Construct tells the builder what to do and in what order.
+// Construct executes the building steps in a specific order.
func (d *Director) Construct() {
d.builder.MakeHeader("Header")
d.builder.MakeBody("Body")
d.builder.MakeFooter("Footer")
}
-// ConcreteBuilder implements Builder interface.
+// ConcreteBuilder implements the Builder interface to construct
+// and assemble parts of the product.
type ConcreteBuilder struct {
product *Product
}
-// MakeHeader builds a header of document..
+// MakeHeader adds a header section to the document.
func (b *ConcreteBuilder) MakeHeader(str string) {
b.product.Content += ""
}
-// MakeBody builds a body of document.
+// MakeBody adds a body section to the document.
func (b *ConcreteBuilder) MakeBody(str string) {
b.product.Content += "" + str + ""
}
-// MakeFooter builds a footer of document.
+// MakeFooter adds a footer section to the document.
func (b *ConcreteBuilder) MakeFooter(str string) {
b.product.Content += ""
}
-// Product implementation.
+// Product represents the complex object being built.
type Product struct {
Content string
}
-// Show returns product.
+// Show returns the final product content.
func (p *Product) Show() string {
return p.Content
}
diff --git a/Creational/FactoryMethod/factory_method.go b/Creational/FactoryMethod/factory_method.go
index 5e39889..55fbd3e 100644
--- a/Creational/FactoryMethod/factory_method.go
+++ b/Creational/FactoryMethod/factory_method.go
@@ -1,11 +1,25 @@
// Package factory_method is an example of the Factory Method pattern.
+//
+// In the following example, we are implementing a product creation system.
+// The Creator defines a factory method that creates products based on an action.
+// Concrete products implement a common interface, allowing them to be used
+// interchangeably.
+//
+// This usage example demonstrates:
+// 1. Creator interface with factory method for creating products
+// 2. Product interface that all products must implement
+// 3. ConcreteCreator that implements the factory method
+// 4. Concrete products (A, B, C) with specific implementations
+//
+// The example is meant to show how to delegate object creation to subclasses
+// and provide a way to create objects without specifying exact classes.
package factory_method
import (
"log"
)
-// action helps clients to find out available actions.
+// action represents the type of product to create.
type action string
const (
@@ -14,27 +28,27 @@ const (
C action = "C"
)
-// Creator provides a factory interface.
+// Creator defines the factory method interface.
type Creator interface {
CreateProduct(action action) Product // Factory Method
}
-// Product provides a product interface.
-// All products returned by factory must provide a single interface.
+// Product defines the interface for all products created by the factory.
type Product interface {
- Use() string // Every product should be usable
+ Use() string // Every product must be usable
}
-// ConcreteCreator implements Creator interface.
+// ConcreteCreator implements the Creator interface.
type ConcreteCreator struct{}
-// NewCreator is the ConcreteCreator constructor.
+// NewCreator creates a new ConcreteCreator.
func NewCreator() Creator {
return &ConcreteCreator{}
}
-// CreateProduct is a Factory Method.
-func (p *ConcreteCreator) CreateProduct(action action) Product {
+// CreateProduct is the factory method that creates products based on action.
+// It returns a product matching the requested action or logs fatal error.
+func (c *ConcreteCreator) CreateProduct(action action) Product {
var product Product
switch action {
@@ -51,32 +65,32 @@ func (p *ConcreteCreator) CreateProduct(action action) Product {
return product
}
-// ConcreteProductA implements product "A".
+// ConcreteProductA implements Product for action A.
type ConcreteProductA struct {
action string
}
-// Use returns product action.
+// Use returns the product's action identifier.
func (p *ConcreteProductA) Use() string {
return p.action
}
-// ConcreteProductB implements product "B".
+// ConcreteProductB implements Product for action B.
type ConcreteProductB struct {
action string
}
-// Use returns product action.
+// Use returns the product's action identifier.
func (p *ConcreteProductB) Use() string {
return p.action
}
-// ConcreteProductC implements product "C".
+// ConcreteProductC implements Product for action C.
type ConcreteProductC struct {
action string
}
-// Use returns product action.
+// Use returns the product's action identifier.
func (p *ConcreteProductC) Use() string {
return p.action
}
diff --git a/Creational/Prototype/prototype.go b/Creational/Prototype/prototype.go
index a9dd13e..ac1ffdf 100644
--- a/Creational/Prototype/prototype.go
+++ b/Creational/Prototype/prototype.go
@@ -1,30 +1,42 @@
-// Package prototype is an example of the Singleton Pattern.
+// Package prototype is an example of the Prototype Pattern.
+//
+// In the following example, we are implementing a cloning system.
+// The Prototyper interface defines a method for cloning objects,
+// allowing new objects to be created by copying existing ones.
+//
+// This usage example demonstrates:
+// 1. Prototyper interface with Clone method
+// 2. Concrete product that implements the cloning interface
+// 3. Creating new objects by cloning existing ones
+//
+// The example is meant to show how to create new objects by copying
+// existing instances, which can be more efficient than creating from scratch.
package prototype
-// Prototyper provides a cloning interface.
+// Prototyper defines the interface for cloning objects.
type Prototyper interface {
Clone() Prototyper
GetName() string
}
-// ConcreteProduct implements product "A"
+// ConcreteProduct implements a product that can be cloned.
type ConcreteProduct struct {
- name string // Имя продукта
+ name string
}
-// NewConcreteProduct is the Prototyper constructor.
+// NewConcreteProduct creates a new product with the given name.
func NewConcreteProduct(name string) Prototyper {
return &ConcreteProduct{
name: name,
}
}
-// GetName returns product name
+// GetName returns the product's name.
func (p *ConcreteProduct) GetName() string {
return p.name
}
-// Clone returns a cloned object.
+// Clone creates and returns a copy of the product.
func (p *ConcreteProduct) Clone() Prototyper {
return &ConcreteProduct{p.name}
}
diff --git a/Creational/README.md b/Creational/README.md
index 29ea31f..cd3b1ee 100644
--- a/Creational/README.md
+++ b/Creational/README.md
@@ -1,23 +1,22 @@
-
## Порождающие паттерны (Creational)
Порождающие паттерны делятся на два типа:
1. Паттерны уровня класса
-2. Паттерны уровня объекта.
+2. Паттерны уровня объекта
-Паттерны уровня класса изменяют класс создаваемого объекта с помощью наследования.
+Паттерны уровня класса используют наследование, чтобы изменять класс создаваемого объекта.
-Паттерны уровня объекта создают новые объекты с помощью других объектов.
+Паттерны уровня объекта делегируют создание объектов другим объектам.
К паттернам уровня класса относится только «Фабричный метод».
-Порождающие паттерны отвечают за создание классов и объектов. Другими словами порождают классы и порождают объекты.
+Порождающие паттерны отвечают за создание классов и объектов. Они абстрагируют процесс инстанцирования, позволяя сделать систему независимой от способа создания, композиции и представления объектов.
* [Абстрактная фабрика (Abstract Factory)](AbstractFactory)
* [Строитель (Builder)](Builder)
-* [Фабричный метод (Factory Method)](FactoryMethod)
-* [Прототип (Prototype)](Prototype)
-* [Одиночка (Singleton)](Singleton)
+* [Фабричный метод (Factory Method)](FactoryMethod)
+* [Прототип (Prototype)](Prototype)
+* [Одиночка (Singleton)](Singleton)
## -~- THE END -~-
\ No newline at end of file
diff --git a/Creational/Singleton/singleton.go b/Creational/Singleton/singleton.go
index ed1300d..ba2e082 100644
--- a/Creational/Singleton/singleton.go
+++ b/Creational/Singleton/singleton.go
@@ -1,12 +1,25 @@
// Package singleton is an example of the Singleton Pattern.
+//
+// In the following example, we are implementing a singleton that ensures
+// only one instance of a type is created. This is useful for shared resources
+// like configuration, connection pools, or logging.
+//
+// This usage example demonstrates:
+// 1. Private instance variable that holds the single instance
+// 2. sync.Once to ensure thread-safe lazy initialization
+// 3. GetInstance function that returns the singleton instance
+//
+// The example is meant to show how to guarantee that a type has only one
+// instance and provide a global point of access to it.
package singleton
import (
"sync"
)
-// Singleton implementation.
+// Singleton represents a type that should have only one instance.
type Singleton struct {
+ // Any fields can be added here
}
var (
@@ -14,7 +27,9 @@ var (
once sync.Once
)
-// GetInstance returns singleton
+// GetInstance returns the singleton instance.
+// It creates the instance on the first call using sync.Once for
+// thread-safe lazy initialization.
func GetInstance() *Singleton {
once.Do(func() {
instance = &Singleton{}
diff --git a/Structural/Adapter/adapter.go b/Structural/Adapter/adapter.go
index 0b2c059..d28644a 100644
--- a/Structural/Adapter/adapter.go
+++ b/Structural/Adapter/adapter.go
@@ -1,31 +1,43 @@
// Package adapter is an example of the Adapter Pattern.
+//
+// In the following example, we are adapting an existing Adaptee to work with
+// a Target interface that our system expects. The Adapter translates calls
+// from Target interface methods to Adaptee methods.
+//
+// This usage example demonstrates:
+// 1. Target interface that the client expects to work with
+// 2. Adaptee that has a different interface
+// 3. Adapter that bridges between Target and Adaptee
+//
+// The example is meant to show how to make incompatible interfaces work together
+// without modifying existing code.
package adapter
-// Target provides an interface with which the system should work.
+// Target defines the interface that the client uses.
type Target interface {
Request() string
}
-// Adaptee implements system to be adapted.
+// Adaptee represents the existing system with an incompatible interface.
type Adaptee struct {
}
-// NewAdapter is the Adapter constructor.
+// NewAdapter creates a new adapter that wraps the adaptee.
func NewAdapter(adaptee *Adaptee) Target {
return &Adapter{adaptee}
}
-// SpecificRequest implementation.
+// SpecificRequest is the adaptee's existing method.
func (a *Adaptee) SpecificRequest() string {
return "Request"
}
-// Adapter implements Target interface and is an adapter.
+// Adapter adapts the Adaptee to the Target interface.
type Adapter struct {
*Adaptee
}
-// Request is an adaptive method.
+// Request implements the Target interface by calling the adaptee's method.
func (a *Adapter) Request() string {
return a.SpecificRequest()
}
diff --git a/Structural/Bridge/bridge.go b/Structural/Bridge/bridge.go
index c0faf4d..1d69c21 100644
--- a/Structural/Bridge/bridge.go
+++ b/Structural/Bridge/bridge.go
@@ -1,56 +1,70 @@
// Package bridge is an example of the Bridge Pattern.
+//
+// In the following example, we are implementing a car and engine system.
+// The Bridge pattern decouples an abstraction (Car) from its implementation (Engine)
+// so they can vary independently. Different cars can use different engines
+// without modifying either hierarchy.
+//
+// This usage example demonstrates:
+// 1. Abstraction (Car) that depends on implementation interface
+// 2. Implementation interface (Enginer) that defines engine behavior
+// 3. Concrete implementations (Suzuki, Honda, Lada engines)
+// 4. Client can combine any car with any engine
+//
+// The example is meant to show how to separate abstraction from implementation
+// and allow them to evolve independently.
package bridge
-// Carer provides car interface.
+// Carer defines the abstraction interface for cars.
type Carer interface {
Rase() string
}
-// Enginer provides engine interface.
+// Enginer defines the implementation interface for engines.
type Enginer interface {
GetSound() string
}
-// Car implementation.
+// Car implements the abstraction and maintains a reference to an engine.
type Car struct {
engine Enginer
}
-// NewCar is the Car constructor.
+// NewCar creates a new car with the specified engine.
func NewCar(engine Enginer) Carer {
return &Car{
engine: engine,
}
}
-// Rase implementation.
+// Rase returns the sound of the car's engine when started.
func (c *Car) Rase() string {
return c.engine.GetSound()
}
-// EngineSuzuki implements Suzuki engine.
+// EngineSuzuki implements a Suzuki engine.
type EngineSuzuki struct {
}
-// GetSound returns sound of the engine.
+// GetSound returns the distinctive sound of a Suzuki engine.
func (e *EngineSuzuki) GetSound() string {
return "SssuuuuZzzuuuuKkiiiii"
}
-// EngineHonda implements Honda engine.
+// EngineHonda implements a Honda engine.
type EngineHonda struct {
}
-// GetSound returns sound of the engine.
+// GetSound returns the distinctive sound of a Honda engine.
func (e *EngineHonda) GetSound() string {
return "HhoooNnnnnnnnnDddaaaaaaa"
}
-// EngineLada implements Lada engine.
+// EngineLada implements a Lada engine.
type EngineLada struct {
}
-// GetSound returns sound of the engine.
+// GetSound returns the distinctive sound of a Lada engine.
func (e *EngineLada) GetSound() string {
return "PhhhhPhhhhPhPhPhPhPh"
}
diff --git a/Structural/Composite/composite.go b/Structural/Composite/composite.go
index 5a91df4..94f64f2 100644
--- a/Structural/Composite/composite.go
+++ b/Structural/Composite/composite.go
@@ -1,36 +1,49 @@
// Package composite is an example of the Composite Pattern.
+//
+// In the following example, we are implementing a file system tree.
+// The Composite pattern allows clients to treat individual objects (File)
+// and compositions of objects (Directory) uniformly through a common interface.
+//
+// This usage example demonstrates:
+// 1. Component interface that defines operations for both leaf and composite
+// 2. Leaf (File) that represents end objects with no children
+// 3. Composite (Directory) that stores child components
+// 4. Uniform traversal and printing of tree structure
+//
+// The example is meant to show how to compose objects into tree structures
+// and work with them as if they were individual objects.
package composite
-// Component provides an interface for branches and leaves of a tree.
+// Component defines the interface for both files and directories.
type Component interface {
- Add(child Component)
- Name() string
- Child() []Component
- Print(prefix string) string
+ Add(child Component) // Add a child component (no-op for files)
+ Name() string // Get component name
+ Child() []Component // Get child components (empty for files)
+ Print(prefix string) string // Print tree structure
}
-// Directory implements branches of a tree
+// Directory implements a composite that can contain other components.
type Directory struct {
name string
childs []Component
}
-// Add appends an element to the tree branch.
+// Add appends a child component to this directory.
func (d *Directory) Add(child Component) {
d.childs = append(d.childs, child)
}
-// Name returns name of the Component.
+// Name returns the directory name.
func (d *Directory) Name() string {
return d.name
}
-// Child returns child elements.
+// Child returns all components inside this directory.
func (d *Directory) Child() []Component {
return d.childs
}
-// Print returns the branche in string representation.
+// Print returns the directory and its contents as a formatted string.
func (d *Directory) Print(prefix string) string {
result := prefix + "/" + d.Name() + "\n"
for _, val := range d.Child() {
@@ -39,38 +52,39 @@ func (d *Directory) Print(prefix string) string {
return result
}
-// File implements a leaves of a tree
+// File implements a leaf that cannot have children.
type File struct {
name string
}
-// Add implementation.
+// Add is a no-op for files (they cannot contain children).
func (f *File) Add(child Component) {
+ // Files don't contain other components
}
-// Name returns name of the Component.
+// Name returns the file name.
func (f *File) Name() string {
return f.name
}
-// Child implementation.
+// Child returns an empty slice as files have no children.
func (f *File) Child() []Component {
return []Component{}
}
-// Print returns the leave in string representation.
+// Print returns the file path as a formatted string.
func (f *File) Print(prefix string) string {
return prefix + "/" + f.Name() + "\n"
}
-// NewDirectory is constructor.
+// NewDirectory creates a new directory with the given name.
func NewDirectory(name string) *Directory {
return &Directory{
name: name,
}
}
-// NewFile is constructor.
+// NewFile creates a new file with the given name.
func NewFile(name string) *File {
return &File{
name: name,
diff --git a/Structural/Decorator/decorator.go b/Structural/Decorator/decorator.go
index ed7a8da..5bd4566 100644
--- a/Structural/Decorator/decorator.go
+++ b/Structural/Decorator/decorator.go
@@ -1,26 +1,40 @@
// Package decorator is an example of the Decorator Pattern.
+//
+// In the following example, we are implementing a text decoration system.
+// The Decorator pattern allows behavior to be added to an individual object
+// dynamically without affecting the behavior of other objects from the same class.
+//
+// This usage example demonstrates:
+// 1. Component interface that defines the base behavior
+// 2. ConcreteComponent that provides the core functionality
+// 3. Decorator that wraps a component and adds new behavior
+//
+// The example is meant to show how to attach additional responsibilities
+// to an object dynamically. Decorators provide a flexible alternative to
+// subclassing for extending functionality.
package decorator
-// Component provides an interface for a decorator and component.
+// Component defines the interface for objects that can have responsibilities
+// added to them dynamically.
type Component interface {
Operation() string
}
-// ConcreteComponent implements a component.
+// ConcreteComponent implements the core Component interface.
type ConcreteComponent struct {
}
-// Operation implementation.
+// Operation returns the base string without any decoration.
func (c *ConcreteComponent) Operation() string {
return "I am component!"
}
-// ConcreteDecorator implements a decorator.
+// ConcreteDecorator wraps a Component and adds additional behavior.
type ConcreteDecorator struct {
component Component
}
-// Operation wraps operation of component
+// Operation decorates the component's result with HTML strong tags.
func (d *ConcreteDecorator) Operation() string {
return "" + d.component.Operation() + ""
}
diff --git a/Structural/Facade/facade.go b/Structural/Facade/facade.go
index 062c5cc..a98e1cf 100644
--- a/Structural/Facade/facade.go
+++ b/Structural/Facade/facade.go
@@ -1,11 +1,25 @@
// Package facade is an example of the Facade Pattern.
+//
+// In the following example, we are implementing a simple life simulator.
+// The Facade pattern provides a unified interface to a set of interfaces
+// in a subsystem. Man facade defines a higher-level interface that makes
+// the subsystem easier to use.
+//
+// This usage example demonstrates:
+// 1. Complex subsystems (House, Tree, Child) with their own interfaces
+// 2. Facade (Man) that provides a simple interface to the subsystems
+// 3. Client code that only interacts with the facade
+//
+// The example is meant to show how to provide a simplified interface
+// to a complex subsystem, reducing dependencies and making the system
+// easier to use.
package facade
import (
"strings"
)
-// NewMan creates man.
+// NewMan creates a new Man facade with all subsystems initialized.
func NewMan() *Man {
return &Man{
house: &House{},
@@ -14,14 +28,16 @@ func NewMan() *Man {
}
}
-// Man implements man and facade.
+// Man implements the facade that provides a simple interface to
+// the complex subsystems (House, Tree, Child).
type Man struct {
house *House
tree *Tree
child *Child
}
-// Todo returns that man must do.
+// Todo returns a summary of everything the man needs to do in life.
+// It coordinates the subsystems and combines their results.
func (m *Man) Todo() string {
result := []string{
m.house.Build(),
@@ -31,29 +47,29 @@ func (m *Man) Todo() string {
return strings.Join(result, "\n")
}
-// House implements a subsystem "House"
+// House represents a subsystem for building-related operations.
type House struct {
}
-// Build implementation.
+// Build returns the house building action.
func (h *House) Build() string {
return "Build house"
}
-// Tree implements a subsystem "Tree"
+// Tree represents a subsystem for tree-related operations.
type Tree struct {
}
-// Grow implementation.
+// Grow returns the tree growing action.
func (t *Tree) Grow() string {
return "Tree grow"
}
-// Child implements a subsystem "Child"
+// Child represents a subsystem for child-related operations.
type Child struct {
}
-// Born implementation.
+// Born returns the child birth action.
func (c *Child) Born() string {
return "Child born"
}
diff --git a/Structural/Flyweight/flyweight.go b/Structural/Flyweight/flyweight.go
index 64e1577..50e4dd6 100644
--- a/Structural/Flyweight/flyweight.go
+++ b/Structural/Flyweight/flyweight.go
@@ -1,20 +1,37 @@
// Package flyweight is an example of the Flyweight Pattern.
+//
+// In the following example, we are implementing an image caching system.
+// The Flyweight pattern minimizes memory usage by sharing as much data as possible
+// with similar objects. It separates intrinsic state (shared) from extrinsic
+// state (context-specific).
+//
+// This usage example demonstrates:
+// 1. Flyweight interface defining operations that use extrinsic state
+// 2. Flyweight factory that creates and manages shared flyweights
+// 3. Concrete flyweight storing intrinsic state (filename)
+// 4. Extrinsic state (width, height, opacity) passed during operations
+//
+// The example is meant to show how to efficiently support large numbers
+// of fine-grained objects by sharing common parts of state.
package flyweight
import "fmt"
-// Flyweighter interface
+// Flyweighter defines the interface for flyweight objects.
type Flyweighter interface {
+ // Draw renders the image with provided extrinsic state.
Draw(width, height int, opacity float64) string
}
-// FlyweightFactory implements a factory.
-// If a suitable flyweighter is in pool, then returns it.
+// FlyweightFactory creates and manages flyweight objects.
+// It ensures that flyweights are shared properly by maintaining a pool.
type FlyweightFactory struct {
pool map[string]Flyweighter
}
-// GetFlyweight creates or returns a suitable Flyweighter by state.
+// GetFlyweight returns a flyweight for the given filename.
+// If a flyweight already exists in the pool, it returns the existing one.
+// Otherwise, it creates a new flyweight, adds it to the pool, and returns it.
func (f *FlyweightFactory) GetFlyweight(filename string) Flyweighter {
if f.pool == nil {
f.pool = make(map[string]Flyweighter)
@@ -25,12 +42,16 @@ func (f *FlyweightFactory) GetFlyweight(filename string) Flyweighter {
return f.pool[filename]
}
-// ConcreteFlyweight implements a Flyweighter interface.
+// ConcreteFlyweight implements the Flyweighter interface.
+// It stores intrinsic state (filename) that is shared across contexts.
type ConcreteFlyweight struct {
- filename string // internal state
+ filename string // internal state (shared)
}
-// Draw draws image. Args width, height and opacity is external state.
+// Draw renders the image with the provided extrinsic state.
+// Extrinsic state (width, height, opacity) is passed as parameters
+// and depends on the specific context of use.
func (f *ConcreteFlyweight) Draw(width, height int, opacity float64) string {
- return fmt.Sprintf("draw image: %s, width: %d, height: %d, opacity: %.2f", f.filename, width, height, opacity)
+ return fmt.Sprintf("draw image: %s, width: %d, height: %d, opacity: %.2f",
+ f.filename, width, height, opacity)
}
diff --git a/Structural/Proxy/proxy.go b/Structural/Proxy/proxy.go
index c391e1c..8fc328c 100644
--- a/Structural/Proxy/proxy.go
+++ b/Structural/Proxy/proxy.go
@@ -1,29 +1,48 @@
-// Package proxy is an example of the Adapter Pattern.
+// Package proxy is an example of the Proxy Pattern.
+//
+// In the following example, we are implementing a message proxy.
+// The Proxy pattern provides a surrogate or placeholder for another object
+// to control access to it. The proxy forwards requests to the real subject
+// and can add additional behavior before or after forwarding.
+//
+// This usage example demonstrates:
+// 1. Subject interface common to both RealSubject and Proxy
+// 2. RealSubject that performs the actual work
+// 3. Proxy that controls access and can add behavior
+// 4. Lazy initialization of the real subject
+//
+// The example is meant to show how to use a proxy for lazy loading,
+// access control, logging, or adding extra functionality without
+// modifying the real subject.
package proxy
-// Subject provides an interface for a real subject and its surrogate.
+// Subject defines the common interface for RealSubject and Proxy.
type Subject interface {
Send() string
}
-// Proxy implements a surrogate.
+// Proxy implements a surrogate that controls access to the RealSubject.
+// It can add additional behavior before or after forwarding requests.
type Proxy struct {
realSubject Subject
}
-// Send sends a message
+// Send forwards the request to the RealSubject, creating it if necessary,
+// and decorates the result with HTML strong tags.
func (p *Proxy) Send() string {
+ // Lazy initialization
if p.realSubject == nil {
p.realSubject = &RealSubject{}
}
+ // Additional behavior (decoration) before/after forwarding
return "" + p.realSubject.Send() + ""
}
-// RealSubject implements a real subject
+// RealSubject implements the actual business logic.
type RealSubject struct {
}
-// Send sends a message
+// Send returns the real message from the subject.
func (s *RealSubject) Send() string {
- return "I’ll be back!"
+ return "I'll be back!"
}
diff --git a/Structural/README.md b/Structural/README.md
index 0cfa265..248e8a2 100644
--- a/Structural/README.md
+++ b/Structural/README.md
@@ -1,31 +1,30 @@
-
-### Структурные паттерны (Structural)
+## Структурные паттерны (Structural)
Структурные паттерны делятся на два типа:
1. Паттерны уровня класса
-2. Паттерны уровня объекта.
+2. Паттерны уровня объекта
-Паттерны уровня класса описывают взаимодействия между классами и их подклассами. Такие отношения выражаются путем наследования и реализации классов. Тут базовый класс определяет интерфейс, а подклассы - реализацию.
+Паттерны уровня класса описывают взаимодействие между классами и их подклассами. Такие отношения выражаются через наследование и реализацию интерфейсов. Базовый класс определяет интерфейс, а подклассы предоставляют конкретную реализацию.
-Паттерны уровня объекта описывают взаимодействия между объектами. Такие отношения выражаются связями - ассоциацией, агрегацией и композицией. Тут структуры строятся путем объединения объектов некоторых классов.
+Паттерны уровня объекта описывают взаимодействие между объектами. Такие отношения выражаются через связи: ассоциацию, агрегацию и композицию. Структуры строятся путем объединения объектов различных классов.
-Ассоциация - отношение, когда объекты двух классов могут ссылаться один на другой. Например, свойство класса содержит экземпляр другого класса.
+**Ассоциация** - отношение, при котором объекты двух классов могут ссылаться друг на друга. Например, свойство одного класса содержит экземпляр другого класса.
-Агрегация – частная форма ассоциации. Агрегация применяется, когда один объект должен быть контейнером для других объектов и время существования этих объектов никак не зависит от времени существования объекта контейнера. Вообщем, если контейнер будет уничтожен, то входящие в него объекты не пострадают. Например, мы создали объект, а потом передали его в объект контейнер, каким-либо образом, можно в метод объекта контейнера передать или присвоить сразу свойству контейнера извне. Значит, при удалении контейнера мы ни как не затронем наш созданный объект, который может взаимодействовать и с другими контейнерами.
+**Агрегация** - частная форма ассоциации. Агрегация применяется, когда один объект выступает контейнером для других объектов, но время жизни этих объектов не зависит от времени жизни контейнера. Если контейнер будет уничтожен, входящие в него объекты продолжают существовать. Например, мы создаем объект и передаем его в контейнер через метод или присваиваем свойству. При удалении контейнера объект остается доступным и может использоваться другими контейнерами.
-Композиция – Тоже самое, что и агрегация, но составные объекты не могут существовать отдельно от объекта контейнера и если контейнер будет уничтожен, то всё его содержимое будет уничтожено тоже. Например, мы создали объект в методе объекта контейнера и присвоили его свойству объекта контейнера. Из вне, о нашем созданном объекте никто не знает, значит, при удалении контейнера, созданный объект будет удален так же, т.к. на него нет ссылки извне.
+**Композиция** - более строгая форма агрегации. Составные объекты не могут существовать отдельно от контейнера. Если контейнер уничтожается, всё его содержимое уничтожается тоже. Например, объект создается внутри метода контейнера и присваивается его свойству. Извне об этом объекте никто не знает, поэтому при удалении контейнера объект становится недоступным и удаляется сборщиком мусора.
-К паттернам уровня класса относится только «Адаптер». Смысл его работы в том, что если у вас есть класс и его интерфейс не совместим с библиотеками вашей системы, то что бы разрешить этот конфликт, мы не изменяем код этого класса, а пишем для него адаптер.
+К паттернам уровня класса относится только «Адаптер». Его смысл в том, что если у вас есть класс с несовместимым интерфейсом, вы не изменяете код этого класса, а создаете адаптер, который приводит интерфейс к нужному виду.
-Все структурные паттерны отвечают за создание правильной структуры системы, в которой без труда смогут взаимодействовать между собой уже имеющиеся классы и объекты.
+Структурные паттерны отвечают за построение гибких и эффективных структур системы, позволяя существующим классам и объектам без труда взаимодействовать друг с другом.
-* [Адаптер (Adapter)](Adapter)
-* [Мост (Bridge)](Bridge)
-* [Компоновщик (Composite)](Composite)
-* [Декоратор (Decorator)](Decorator)
-* [Фасад (Facade)](Facade)
-* [Приспособленец (Flyweight)](Flyweight)
-* [Заместитель (Proxy)](Proxy)
+* [Адаптер (Adapter)](Adapter)
+* [Мост (Bridge)](Bridge)
+* [Компоновщик (Composite)](Composite)
+* [Декоратор (Decorator)](Decorator)
+* [Фасад (Facade)](Facade)
+* [Приспособленец (Flyweight)](Flyweight)
+* [Заместитель (Proxy)](Proxy)
-## -~- THE END -~-
+## -~- THE END -~-
\ No newline at end of file
diff --git a/Unsorted/README.md b/Unsorted/README.md
index 7fe2068..b15a303 100644
--- a/Unsorted/README.md
+++ b/Unsorted/README.md
@@ -2,5 +2,5 @@
### Неотсортированные и наброски
* [Спецификация (Specification)](Specification)
-
+* [Пул воркеров (Worker Pool)](WorkerPool)
## -~- THE END -~-
diff --git a/Unsorted/Specification/specification.go b/Unsorted/Specification/specification.go
index 984a9b2..78df15f 100644
--- a/Unsorted/Specification/specification.go
+++ b/Unsorted/Specification/specification.go
@@ -1,30 +1,37 @@
-// Pattern Specification
+// Package specification provides an implementation of the Specification pattern
+// for business rules validation.
//
-// In the following example, we are retrieving invoices and sending them to a collection agency if
+// In the following example, we are retrieving invoices and sending them to a
+// collection agency if:
// 1. they are overdue,
// 2. notices have been sent, and
// 3. they are not already with the collection agency.
+//
// This example is meant to show the end result of how the logic is 'chained' together.
+// The Specification pattern allows you to encapsulate business rules in a
+// reusable and combinable way. Rules can be chained using AND, OR, and NOT
+// operations to create complex validation logic.
//
-// This usage example assumes a previously defined OverdueSpecification class
-// that is satisfied when an invoice's due date is 30 days or older,
-// a NoticeSentSpecification class that is satisfied when three notices
-// have been sent to the customer, and an InCollectionSpecification class
-// that is satisfied when an invoice has already been sent to the collection
-// agency. The implementation of these classes isn't important here.
-
+// This usage example demonstrates:
+// 1. Specification interface with logical combinators (And, Or, Not)
+// 2. BaseSpecification providing default combinator implementations
+// 3. Composite specifications (And, Or, Not) for combining rules
+// 4. Concrete specifications (OverDue, NoticeSent, InCollection)
+// 5. Method chaining for readable business rules
+//
+// The example is meant to show how to build complex business rules from
+// simple, reusable components.
package specification
-// Data for analysis
+// Invoice represents a customer invoice with data needed for business rules.
type Invoice struct {
- Day int
- Notice int
- IsSent bool
+ Day int // Days overdue
+ Notice int // Number of notices sent
+ IsSent bool // Whether already sent to collection
}
-/////
-
-// Invoice Specification Interface
+// Specification defines the interface for business rules that can be
+// evaluated against an Invoice and combined with other specifications.
type Specification interface {
IsSatisfiedBy(Invoice) bool
And(Specification) Specification
@@ -33,137 +40,132 @@ type Specification interface {
Relate(Specification)
}
-/////
-
-// Invoice BaseSpecification
+// BaseSpecification provides default implementations for logical combinators.
+// It should be embedded in all concrete specifications.
type BaseSpecification struct {
Specification
}
-// Check specification
-func (self *BaseSpecification) IsSatisfiedBy(elm Invoice) bool {
+// IsSatisfiedBy provides a default implementation that returns false.
+// Concrete specifications should override this method.
+func (b *BaseSpecification) IsSatisfiedBy(elm Invoice) bool {
return false
}
-// Condition AND
-func (self *BaseSpecification) And(spec Specification) Specification {
- a := &AndSpecification{
- self.Specification, spec,
+// And creates a new specification that requires both conditions to be true.
+func (b *BaseSpecification) And(spec Specification) Specification {
+ and := &AndSpecification{
+ Specification: b.Specification,
+ compare: spec,
}
- a.Relate(a)
- return a
+ and.Relate(and)
+ return and
}
-// Condition OR
-func (self *BaseSpecification) Or(spec Specification) Specification {
- a := &OrSpecification{
- self.Specification, spec,
+// Or creates a new specification that requires at least one condition to be true.
+func (b *BaseSpecification) Or(spec Specification) Specification {
+ or := &OrSpecification{
+ Specification: b.Specification,
+ compare: spec,
}
- a.Relate(a)
- return a
+ or.Relate(or)
+ return or
}
-// Condition NOT
-func (self *BaseSpecification) Not() Specification {
- a := &NotSpecification{
- self.Specification,
+// Not creates a new specification that requires the condition to be false.
+func (b *BaseSpecification) Not() Specification {
+ not := &NotSpecification{
+ Specification: b.Specification,
}
- a.Relate(a)
- return a
+ not.Relate(not)
+ return not
}
-// Relate to specification
-func (self *BaseSpecification) Relate(spec Specification) {
- self.Specification = spec
+// Relate sets the embedded specification reference.
+// This internal method helps composite specifications delegate correctly.
+func (b *BaseSpecification) Relate(spec Specification) {
+ b.Specification = spec
}
-/////
-
-// AndSpecification
+// AndSpecification combines two specifications with logical AND.
type AndSpecification struct {
Specification
compare Specification
}
-// Check specification
-func (self *AndSpecification) IsSatisfiedBy(elm Invoice) bool {
- return self.Specification.IsSatisfiedBy(elm) && self.compare.IsSatisfiedBy(elm)
+// IsSatisfiedBy returns true only if both specifications are satisfied.
+func (a *AndSpecification) IsSatisfiedBy(elm Invoice) bool {
+ return a.Specification.IsSatisfiedBy(elm) && a.compare.IsSatisfiedBy(elm)
}
-/////
-
-// OrSpecification
+// OrSpecification combines two specifications with logical OR.
type OrSpecification struct {
Specification
compare Specification
}
-// Check specification
-func (self *OrSpecification) IsSatisfiedBy(elm Invoice) bool {
- return self.Specification.IsSatisfiedBy(elm) || self.compare.IsSatisfiedBy(elm)
+// IsSatisfiedBy returns true if either specification is satisfied.
+func (o *OrSpecification) IsSatisfiedBy(elm Invoice) bool {
+ return o.Specification.IsSatisfiedBy(elm) || o.compare.IsSatisfiedBy(elm)
}
-/////
-
-// NotSpecification
+// NotSpecification inverts a specification with logical NOT.
type NotSpecification struct {
Specification
}
-// Check specification
-func (self *NotSpecification) IsSatisfiedBy(elm Invoice) bool {
- return !self.Specification.IsSatisfiedBy(elm)
+// IsSatisfiedBy returns true if the wrapped specification is not satisfied.
+func (n *NotSpecification) IsSatisfiedBy(elm Invoice) bool {
+ return !n.Specification.IsSatisfiedBy(elm)
}
-/////
-
-// Invoice's due date is 30 days or older
+// OverDueSpecification is satisfied when an invoice is 30+ days overdue.
type OverDueSpecification struct {
Specification
}
-// Check specification
-func (self *OverDueSpecification) IsSatisfiedBy(elm Invoice) bool {
+// IsSatisfiedBy returns true if the invoice is 30 days or more overdue.
+func (o *OverDueSpecification) IsSatisfiedBy(elm Invoice) bool {
return elm.Day >= 30
}
-// Constructor
+// NewOverDueSpecification creates a new specification for overdue invoices.
func NewOverDueSpecification() Specification {
- a := &OverDueSpecification{&BaseSpecification{}}
- a.Relate(a)
- return a
+ spec := &OverDueSpecification{&BaseSpecification{}}
+ spec.Relate(spec)
+ return spec
}
-// Three notices have been sent to the customer
+// NoticeSentSpecification is satisfied when 3+ notices have been sent.
type NoticeSentSpecification struct {
Specification
}
-// Check specification
-func (self *NoticeSentSpecification) IsSatisfiedBy(elm Invoice) bool {
+// IsSatisfiedBy returns true if the invoice has 3 or more notices sent.
+func (n *NoticeSentSpecification) IsSatisfiedBy(elm Invoice) bool {
return elm.Notice >= 3
}
-// Constructor
+// NewNoticeSentSpecification creates a new specification for notice count.
func NewNoticeSentSpecification() Specification {
- a := &NoticeSentSpecification{&BaseSpecification{}}
- a.Relate(a)
- return a
+ spec := &NoticeSentSpecification{&BaseSpecification{}}
+ spec.Relate(spec)
+ return spec
}
-// Invoice has already been sent to the collection agency.
+// InCollectionSpecification is satisfied when invoice is NOT yet in collection.
type InCollectionSpecification struct {
Specification
}
-// Check specification
-func (self *InCollectionSpecification) IsSatisfiedBy(elm Invoice) bool {
+// IsSatisfiedBy returns true if the invoice has NOT been sent to collection.
+func (i *InCollectionSpecification) IsSatisfiedBy(elm Invoice) bool {
return !elm.IsSent
}
-// Constructor
+// NewInCollectionSpecification creates a new specification for collection status.
func NewInCollectionSpecification() Specification {
- a := &InCollectionSpecification{&BaseSpecification{}}
- a.Relate(a)
- return a
+ spec := &InCollectionSpecification{&BaseSpecification{}}
+ spec.Relate(spec)
+ return spec
}
diff --git a/Unsorted/WorkerPool/README.md b/Unsorted/WorkerPool/README.md
new file mode 100644
index 0000000..8f1436f
--- /dev/null
+++ b/Unsorted/WorkerPool/README.md
@@ -0,0 +1,18 @@
+## Пул воркеров (Worker Pool)
+
+Паттерн Worker Pool относится к группе паттернов конкурентного выполнения.
+
+Часто в приложениях требуется выполнить множество однотипных задач, и последовательная обработка занимает слишком много времени. Например, нужно обработать тысячи HTTP-запросов, файлов или сообщений из очереди. В таких случаях следует использовать паттерн Worker Pool.
+
+Смысл работы этого паттерна в том, что мы создаём фиксированное количество воркеров (горутин), которые постоянно ожидают поступления задач. Когда задача появляется, свободный воркер немедленно приступает к её выполнению. Другими словами, Worker Pool распределяет нагрузку и ограничивает количество одновременно выполняемых операций.
+
+Требуется для реализации:
+
+1. Очередь задач — канал, через который поступают задания;
+2. Пул воркеров — фиксированное количество горутин, выполняющих задачи;
+3. Механизм завершения — способ корректно остановить все воркеры;
+4. Сбор результатов — опциональный канал для получения результатов работы.
+
+[!] В описании паттерна применяются общие понятия. Применимо к языку Go, это горутины и каналы для организации конкурентного выполнения.
+
+## -~- THE END -~-
\ No newline at end of file
diff --git a/Unsorted/WorkerPool/worker_pool.go b/Unsorted/WorkerPool/worker_pool.go
new file mode 100644
index 0000000..2ad2af5
--- /dev/null
+++ b/Unsorted/WorkerPool/worker_pool.go
@@ -0,0 +1,99 @@
+// Package workerpool provides an implementation of the Worker Pool pattern
+// for concurrent task processing.
+//
+// In the following example, we are processing a large number of tasks
+// concurrently using a fixed pool of workers. This approach allows us to
+// control the degree of parallelism and prevent resource exhaustion.
+//
+// This usage example demonstrates:
+// 1. Creating a pool with one worker per CPU core
+// 2. Distributing 1000 tasks through a channel
+// 3. Collecting results from all workers
+// 4. Graceful shutdown using context
+//
+// The workers simulate work with a one-second delay and return the square
+// of each input value. This example is meant to show the end result of how
+// the tasks are distributed and results are collected.
+package workerpool
+
+import (
+ "context"
+ "fmt"
+ "runtime"
+ "sync"
+ "time"
+)
+
+// WorkerPool demonstrates a basic worker pool implementation.
+// It creates a pool of workers, distributes 1000 tasks, and collects results.
+//
+// The function uses:
+// - context.WithCancel for graceful shutdown
+// - tasks channel for distributing work
+// - results channel for collecting output
+// - sync.WaitGroup for coordinating worker completion
+func WorkerPool() {
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ tasks := make(chan int)
+ results := make(chan int)
+ wg := &sync.WaitGroup{}
+
+ // Start workers (one per CPU core)
+ for i := 0; i < runtime.NumCPU(); i++ {
+ wg.Add(1)
+ go func(workerID int) {
+ defer wg.Done()
+ worker(ctx, workerID, tasks, results)
+ }(i)
+ }
+
+ // Send tasks (producer)
+ go func() {
+ defer close(tasks)
+ for i := 0; i < 1000; i++ {
+ tasks <- i
+ }
+ }()
+
+ // Close results when all workers are done (collector coordinator)
+ go func() {
+ wg.Wait()
+ close(results)
+ }()
+
+ // Collect and print results (consumer)
+ for result := range results {
+ fmt.Printf("Result: %d\n", result)
+ }
+}
+
+// worker processes tasks from tasks channel and sends results to results channel.
+// It runs until context is cancelled or tasks channel is closed.
+//
+// Each worker:
+// - Receives a task from the tasks channel
+// - Simulates work with a one-second delay
+// - Sends the result (input squared) to the results channel
+// - Exits when context is done or tasks channel is closed
+//
+// The worker ID is used only for logging to demonstrate distribution.
+func worker(ctx context.Context, id int, tasks <-chan int, results chan<- int) {
+ for {
+ select {
+ case <-ctx.Done():
+ // Context cancelled - shut down gracefully
+ return
+ case val, ok := <-tasks:
+ if !ok {
+ // Tasks channel closed - no more work
+ return
+ }
+ fmt.Printf("Worker %d received %d\n", id, val)
+ time.Sleep(time.Second)
+ results <- val * val
+ fmt.Printf("Worker %d processed %d\n", id, val)
+ }
+ }
+}
diff --git a/Unsorted/WorkerPool/worker_pool_test.go b/Unsorted/WorkerPool/worker_pool_test.go
new file mode 100644
index 0000000..05bbf05
--- /dev/null
+++ b/Unsorted/WorkerPool/worker_pool_test.go
@@ -0,0 +1,196 @@
+package workerpool
+
+import (
+ "context"
+ "sync"
+ "testing"
+ "time"
+)
+
+func TestWorkerPool(t *testing.T) {
+ // Create context with timeout to prevent hanging tests
+ ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
+ defer cancel()
+
+ tasks := make(chan int, 10)
+ results := make(chan int, 10)
+ wg := &sync.WaitGroup{}
+
+ // Start 2 workers for the test
+ numWorkers := 2
+ for i := 0; i < numWorkers; i++ {
+ wg.Add(1)
+ go func(workerID int) {
+ defer wg.Done()
+ worker(ctx, workerID, tasks, results)
+ }(i)
+ }
+
+ // Send 5 tasks
+ go func() {
+ for i := 1; i <= 5; i++ {
+ tasks <- i
+ }
+ close(tasks)
+ }()
+
+ // Wait for workers to finish in a separate goroutine
+ go func() {
+ wg.Wait()
+ close(results)
+ }()
+
+ // Collect results
+ received := make(map[int]bool)
+ for result := range results {
+ received[result] = true
+ }
+
+ // Verify we received all squares of numbers 1 through 5
+ expected := map[int]bool{
+ 1: true, // 1*1
+ 4: true, // 2*2
+ 9: true, // 3*3
+ 16: true, // 4*4
+ 25: true, // 5*5
+ }
+
+ for exp := range expected {
+ if !received[exp] {
+ t.Errorf("Expected result %d not found in results", exp)
+ }
+ }
+
+ if len(received) != len(expected) {
+ t.Errorf("Expected %d results, got %d", len(expected), len(received))
+ }
+}
+
+func TestWorkerPoolCancellation(t *testing.T) {
+ // Context is cancelled immediately
+ ctx, cancel := context.WithCancel(context.Background())
+ cancel() // Cancel before starting
+
+ tasks := make(chan int, 10)
+ wg := &sync.WaitGroup{}
+
+ workerStarted := make(chan bool)
+ workerDone := make(chan bool)
+
+ // Start one worker
+ wg.Add(1)
+ go func() {
+ workerStarted <- true
+ defer func() {
+ wg.Done()
+ workerDone <- true
+ }()
+
+ for {
+ select {
+ case <-ctx.Done():
+ return
+ case _, ok := <-tasks:
+ if !ok {
+ return
+ }
+ // Should never reach here as context is already cancelled
+ t.Error("Worker received task after cancellation")
+ }
+ }
+ }()
+
+ <-workerStarted // Wait for worker to start
+
+ // Try to send a task
+ select {
+ case tasks <- 42:
+ // If sent, give some time for processing
+ time.Sleep(10 * time.Millisecond)
+ default:
+ // Channel might be closed
+ }
+
+ close(tasks)
+ wg.Wait()
+
+ // Verify worker exited
+ select {
+ case <-workerDone:
+ // Good, worker exited
+ case <-time.After(time.Second):
+ t.Error("Worker did not exit after cancellation")
+ }
+}
+
+func TestWorkerPoolClosedTasks(t *testing.T) {
+ ctx := context.Background()
+ tasks := make(chan int)
+ results := make(chan int, 5)
+ wg := &sync.WaitGroup{}
+
+ // Start worker
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ worker(ctx, 1, tasks, results)
+ }()
+
+ // Send one task and close
+ go func() {
+ tasks <- 7
+ close(tasks)
+ }()
+
+ // Wait for result
+ select {
+ case res := <-results:
+ if res != 49 { // 7*7
+ t.Errorf("Expected 49, got %d", res)
+ }
+ case <-time.After(2 * time.Second):
+ t.Error("Timeout waiting for result")
+ }
+
+ wg.Wait()
+}
+
+func TestWorkerPoolManyTasks(t *testing.T) {
+ ctx := context.Background()
+ tasks := make(chan int, 100)
+ results := make(chan int, 100)
+ wg := &sync.WaitGroup{}
+
+ // Start 4 workers
+ for i := 0; i < 4; i++ {
+ wg.Add(1)
+ go func(id int) {
+ defer wg.Done()
+ worker(ctx, id, tasks, results)
+ }(i)
+ }
+
+ // Send 20 tasks
+ go func() {
+ for i := 0; i < 20; i++ {
+ tasks <- i
+ }
+ close(tasks)
+ }()
+
+ // Close results after all workers are done
+ go func() {
+ wg.Wait()
+ close(results)
+ }()
+
+ // Count results
+ count := 0
+ for range results {
+ count++
+ }
+
+ if count != 20 {
+ t.Errorf("Expected 20 results, got %d", count)
+ }
+}