├── .gitattributes
├── .gitignore
├── Behavioral
├── ChainOfResponsibility
│ ├── README.md
│ ├── chain_of_responsibility.go
│ └── chain_of_responsibility_test.go
├── Command
│ ├── README.md
│ ├── command.go
│ └── command_test.go
├── Iterator
│ ├── README.md
│ ├── iterator.go
│ └── iterator_test.go
├── Mediator
│ ├── README.md
│ ├── mediator.go
│ └── mediator_test.go
├── Memento
│ ├── README.md
│ ├── memento.go
│ └── memento_test.go
├── Observer
│ ├── README.md
│ ├── observer.go
│ └── observer_test.go
├── README.md
├── State
│ ├── README.md
│ ├── state.go
│ └── state_test.go
├── Strategy
│ ├── README.md
│ ├── strategy.go
│ └── strategy_test.go
├── TemplateMethod
│ ├── README.md
│ ├── template_method.go
│ └── template_method_test.go
└── Visitor
│ ├── README.md
│ ├── visitor.go
│ └── visitor_test.go
├── Creational
├── AbstractFactory
│ ├── README.md
│ ├── abstract_factory.go
│ └── abstract_factory_test.go
├── Builder
│ ├── README.md
│ ├── builder.go
│ └── builder_test.go
├── FactoryMethod
│ ├── README.md
│ ├── factory_method.go
│ └── factory_method_test.go
├── Prototype
│ ├── README.md
│ ├── prototype.go
│ └── prototype_test.go
├── README.md
└── Singleton
│ ├── README.md
│ ├── singleton.go
│ └── singleton_test.go
├── LICENSE
├── README.md
├── Structural
├── Adapter
│ ├── README.md
│ ├── adapter.go
│ └── adapter_test.go
├── Bridge
│ ├── README.md
│ ├── bridge.go
│ └── bridge_test.go
├── Composite
│ ├── README.md
│ ├── composite.go
│ └── composite_test.go
├── Decorator
│ ├── README.md
│ ├── decorator.go
│ └── decorator_test.go
├── Facade
│ ├── README.md
│ ├── facade.go
│ └── facade_test.go
├── Flyweight
│ ├── README.md
│ ├── flyweight.go
│ └── flyweight_test.go
├── Proxy
│ ├── README.md
│ ├── proxy.go
│ └── proxy_test.go
└── README.md
└── Unsorted
├── README.md
└── Specification
├── README.md
├── specification.go
└── specification_test.go
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Build results
2 | bin/
3 | pkg/
4 |
5 | #Bat
6 | *.bat
7 |
8 | # Log
9 | *.log
10 |
11 | # Windows image file caches
12 | Thumbs.db
13 |
14 | # Folder config file
15 | Desktop.ini
16 |
17 | # Mac crap
18 | .DS_Store
19 |
--------------------------------------------------------------------------------
/Behavioral/ChainOfResponsibility/README.md:
--------------------------------------------------------------------------------
1 |
2 | ## Цепочка ответственности (Chain Of Responsibility)
3 |
4 | Паттерн Chain Of Responsibility относится к поведенческим паттернам уровня объекта.
5 |
6 | Паттерн Chain Of Responsibility позволяет избежать привязки объекта-отправителя запроса к объекту-получателю запроса, при этом давая шанс обработать этот запрос нескольким объектам. Получатели связываются в цепочку, и запрос передается по цепочке, пока не будет обработан каким-то объектом.
7 |
8 | По сути это цепочка обработчиков, которые по очереди получают запрос, а затем решают, обрабатывать его или нет. Если запрос не обработан, то он передается дальше по цепочке. Если же он обработан, то паттерн сам решает передавать его дальше или нет. Если запрос не обработан ни одним обработчиком, то он просто теряется.
9 |
10 | Требуется для реализации:
11 |
12 | 1. Базовый абстрактный класс Handler, описывающий интерфейс обработчиков в цепочки;
13 | 2. Класс ConcreteHandlerA, реализующий конкретный обработчик A;
14 | 3. Класс ConcreteHandlerB, реализующий конкретный обработчик B;
15 | 4. Класс ConcreteHandlerC, реализующий конкретный обработчик C;
16 |
17 | Обратите внимание, что вместо хранения ссылок на всех кандидатов-получателей запроса, каждый отправитель хранит единственную ссылку на начало цепочки, а каждый получатель имеет единственную ссылку на своего преемника - последующий элемент в цепочке.
18 |
19 | [!] В описании паттерна применяются общие понятия, такие как Класс, Объект, Абстрактный класс. Применимо к языку Go, это Пользовательский Тип, Значение этого Типа и Интерфейс. Также в языке Go за место общепринятого наследования используется агрегирование и встраивание.
20 |
21 | ## -~- THE END -~-
--------------------------------------------------------------------------------
/Behavioral/ChainOfResponsibility/chain_of_responsibility.go:
--------------------------------------------------------------------------------
1 | // Package chain_of_responsibility is an example of the Chain Of Responsibility Pattern.
2 | package chain_of_responsibility
3 |
4 | // Handler provides a handler interface.
5 | type Handler interface {
6 | SendRequest(message int) string
7 | }
8 |
9 | // ConcreteHandlerA implements handler "A".
10 | type ConcreteHandlerA struct {
11 | next Handler
12 | }
13 |
14 | // SendRequest implementation.
15 | func (h *ConcreteHandlerA) SendRequest(message int) (result string) {
16 | if message == 1 {
17 | result = "Im handler 1"
18 | } else if h.next != nil {
19 | result = h.next.SendRequest(message)
20 | }
21 | return
22 | }
23 |
24 | // ConcreteHandlerB implements handler "B".
25 | type ConcreteHandlerB struct {
26 | next Handler
27 | }
28 |
29 | // SendRequest implementation.
30 | func (h *ConcreteHandlerB) SendRequest(message int) (result string) {
31 | if message == 2 {
32 | result = "Im handler 2"
33 | } else if h.next != nil {
34 | result = h.next.SendRequest(message)
35 | }
36 | return
37 | }
38 |
39 | // ConcreteHandlerC implements handler "C".
40 | type ConcreteHandlerC struct {
41 | next Handler
42 | }
43 |
44 | // SendRequest implementation.
45 | func (h *ConcreteHandlerC) SendRequest(message int) (result string) {
46 | if message == 3 {
47 | result = "Im handler 3"
48 | } else if h.next != nil {
49 | result = h.next.SendRequest(message)
50 | }
51 | return
52 | }
53 |
--------------------------------------------------------------------------------
/Behavioral/ChainOfResponsibility/chain_of_responsibility_test.go:
--------------------------------------------------------------------------------
1 | package chain_of_responsibility
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestChainOfResponsibility(t *testing.T) {
8 |
9 | expect := "Im handler 2"
10 |
11 | handlers := &ConcreteHandlerA{
12 | next: &ConcreteHandlerB{
13 | next: &ConcreteHandlerC{},
14 | },
15 | }
16 |
17 | result := handlers.SendRequest(2)
18 |
19 | if result != expect {
20 | t.Errorf("Expect result to equal %s, but %s.\n", expect, result)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Behavioral/Command/README.md:
--------------------------------------------------------------------------------
1 |
2 | ## Команда (Command)
3 |
4 | Паттерн Command относится к поведенческим паттернам уровня объекта.
5 |
6 | Паттерн Command позволяет представить запрос в виде объекта. Из этого следует, что команда - это объект. Такие запросы, например, можно ставить в очередь, отменять или возобновлять.
7 |
8 | В этом паттерне мы оперируем следующими понятиями:
9 | Command - запрос в виде объекта на выполнение;
10 | Receiver - объект-получатель запроса, который будет обрабатывать нашу команду;
11 | Invoker - объект-инициатор запроса.
12 |
13 | Паттерн Command отделяет объект, инициирующий операцию, от объекта, который знает, как ее выполнить. Единственное, что должен знать инициатор, это как отправить команду.
14 |
15 | Требуется для реализации:
16 |
17 | 1. Базовый абстрактный класс Command описывающий интерфейс команды;
18 | 2. Класс ConcreteCommand, реализующий команду;
19 | 3. Класс Invoker, реализующий инициатора, записывающий команду и провоцирующий её выполнение;
20 | 4. Класс Receiver, реализующий получателя и имеющий набор действий, которые команда можем запрашивать;
21 |
22 | Invoker умеет складывать команды в стопку и инициировать их выполнение по какому-то событию. Обратившись к Invoker можно отменить команду, пока та не выполнена.
23 |
24 | ConcreteCommand содержит в себе запросы к Receiver, которые тот должен выполнять. В свою очередь Receiver содержит только набор действий (Actions), которые выполняются при обращении к ним из ConcreteCommand.
25 |
26 | [!] В описании паттерна применяются общие понятия, такие как Класс, Объект, Абстрактный класс. Применимо к языку Go, это Пользовательский Тип, Значение этого Типа и Интерфейс. Также в языке Go за место общепринятого наследования используется агрегирование и встраивание.
27 |
28 | ## -~- THE END -~-
--------------------------------------------------------------------------------
/Behavioral/Command/command.go:
--------------------------------------------------------------------------------
1 | // Package command is an example of the Command Pattern.
2 | package command
3 |
4 | // Command provides a command interface.
5 | type Command interface {
6 | Execute() string
7 | }
8 |
9 | // ToggleOnCommand implements the Command interface.
10 | type ToggleOnCommand struct {
11 | receiver *Receiver
12 | }
13 |
14 | // Execute command.
15 | func (c *ToggleOnCommand) Execute() string {
16 | return c.receiver.ToggleOn()
17 | }
18 |
19 | // ToggleOffCommand implements the Command interface.
20 | type ToggleOffCommand struct {
21 | receiver *Receiver
22 | }
23 |
24 | // Execute command.
25 | func (c *ToggleOffCommand) Execute() string {
26 | return c.receiver.ToggleOff()
27 | }
28 |
29 | // Receiver implementation.
30 | type Receiver struct {
31 | }
32 |
33 | // ToggleOn implementation.
34 | func (r *Receiver) ToggleOn() string {
35 | return "Toggle On"
36 | }
37 |
38 | // ToggleOff implementation.
39 | func (r *Receiver) ToggleOff() string {
40 | return "Toggle Off"
41 | }
42 |
43 | // Invoker implementation.
44 | type Invoker struct {
45 | commands []Command
46 | }
47 |
48 | // StoreCommand adds command.
49 | func (i *Invoker) StoreCommand(command Command) {
50 | i.commands = append(i.commands, command)
51 | }
52 |
53 | // UnStoreCommand removes command.
54 | func (i *Invoker) UnStoreCommand() {
55 | if len(i.commands) != 0 {
56 | i.commands = i.commands[:len(i.commands)-1]
57 | }
58 | }
59 |
60 | // Execute all commands.
61 | func (i *Invoker) Execute() string {
62 | var result string
63 | for _, command := range i.commands {
64 | result += command.Execute() + "\n"
65 | }
66 | return result
67 | }
68 |
--------------------------------------------------------------------------------
/Behavioral/Command/command_test.go:
--------------------------------------------------------------------------------
1 | package command
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestCommand(t *testing.T) {
8 |
9 | expect := "Toggle On\n" +
10 | "Toggle Off\n"
11 |
12 | invoker := &Invoker{}
13 | receiver := &Receiver{}
14 |
15 | invoker.StoreCommand(&ToggleOnCommand{receiver: receiver})
16 | invoker.StoreCommand(&ToggleOffCommand{receiver: receiver})
17 |
18 | result := invoker.Execute()
19 |
20 | if result != expect {
21 | t.Errorf("Expect result to equal %s, but %s.\n", expect, result)
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Behavioral/Iterator/README.md:
--------------------------------------------------------------------------------
1 |
2 | ## Итератор (Iterator)
3 |
4 | Паттерн Iterator относится к поведенческим паттернам уровня объекта.
5 |
6 | Паттерн Iterator предоставляет механизм обхода коллекций объектов не раскрывая их внутреннего представления.
7 |
8 | Зачастую этот паттерн используется вместо массива объектов, чтобы не только предоставить доступ к элементам, но и наделить некоторой логикой.
9 |
10 | Iterator представляет собой общий интерфейс, позволяющий реализовать произвольную логику итераций.
11 |
12 | Требуется для реализации:
13 |
14 | 1. Интерфейс Iterator описывающий набор методов для доступа к коллекции;
15 | 2. Класс ConcreteIterator, реализующий интерфейс Iterator. Следит за позицией текущего элемента при переборе коллекции (Aggregate).;
16 | 3. Интерфейс Aggregate описывающий набор методов коллекции объектов;
17 | 4. Класс ConcreteAggregate, реализующий интерфейс Aggregate и хранящий в себе элементы коллекции.
18 |
19 | [!] В описании паттерна применяются общие понятия, такие как Класс, Объект, Абстрактный класс. Применимо к языку Go, это Пользовательский Тип, Значение этого Типа и Интерфейс. Также в языке Go за место общепринятого наследования используется агрегирование и встраивание.
20 |
21 | ## -~- THE END -~-
22 |
--------------------------------------------------------------------------------
/Behavioral/Iterator/iterator.go:
--------------------------------------------------------------------------------
1 | // Package iterator is an example of the Iterator Pattern.
2 | package iterator
3 |
4 | // Iterator provides a iterator interface.
5 | type Iterator interface {
6 | Index() int
7 | Value() interface{}
8 | Has() bool
9 | Next()
10 | Prev()
11 | Reset()
12 | End()
13 | }
14 |
15 | // Aggregate provides a collection interface.
16 | type Aggregate interface {
17 | Iterator() Iterator
18 | }
19 |
20 | // BookIterator implements the Iterator interface.
21 | type BookIterator struct {
22 | shelf *BookShelf
23 | index int
24 | internal int
25 | }
26 |
27 | // Index returns current index
28 | func (i *BookIterator) Index() int {
29 | return i.index
30 | }
31 |
32 | // Value returns current value
33 | func (i *BookIterator) Value() interface{} {
34 | return i.shelf.Books[i.index]
35 | }
36 |
37 | // Has implementation.
38 | func (i *BookIterator) Has() bool {
39 | if i.internal < 0 || i.internal >= len(i.shelf.Books) {
40 | return false
41 | }
42 | return true
43 | }
44 |
45 | // Next goes to the next item.
46 | func (i *BookIterator) Next() {
47 | i.internal++
48 | if i.Has() {
49 | i.index++
50 | }
51 | }
52 |
53 | // Prev goes to the previous item.
54 | func (i *BookIterator) Prev() {
55 | i.internal--
56 | if i.Has() {
57 | i.index--
58 | }
59 | }
60 |
61 | // Reset resets iterator.
62 | func (i *BookIterator) Reset() {
63 | i.index = 0
64 | i.internal = 0
65 | }
66 |
67 | // End goes to the last item.
68 | func (i *BookIterator) End() {
69 | i.index = len(i.shelf.Books) - 1
70 | i.internal = i.index
71 | }
72 |
73 | // BookShelf implements the Aggregate interface.
74 | type BookShelf struct {
75 | Books []*Book
76 | }
77 |
78 | // Iterator creates and returns the iterator over the collection.
79 | func (b *BookShelf) Iterator() Iterator {
80 | return &BookIterator{shelf: b}
81 | }
82 |
83 | // Add adds an item to the collection.
84 | func (b *BookShelf) Add(book *Book) {
85 | b.Books = append(b.Books, book)
86 | }
87 |
88 | // Book implements a item of the collection.
89 | type Book struct {
90 | Name string
91 | }
92 |
--------------------------------------------------------------------------------
/Behavioral/Iterator/iterator_test.go:
--------------------------------------------------------------------------------
1 | package iterator
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestIterator(t *testing.T) {
8 |
9 | shelf := new(BookShelf)
10 |
11 | books := []string{"A", "B", "C", "D", "E", "F"}
12 |
13 | for _, book := range books {
14 | shelf.Add(&Book{Name: book})
15 | }
16 |
17 | for iterator := shelf.Iterator(); iterator.Has(); iterator.Next() {
18 | index, value := iterator.Index(), iterator.Value().(*Book)
19 | if value.Name != books[index] {
20 | t.Errorf("Expect Book.Name to %s, but %s", books[index], value.Name)
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Behavioral/Mediator/README.md:
--------------------------------------------------------------------------------
1 |
2 | ## Посредник (Mediator)
3 |
4 | Паттерн Mediator относится к поведенческим паттернам уровня объекта.
5 |
6 | Паттерн Mediator предоставляет объект-посредник, скрывающий способ взаимодействия множества других объектов-коллег. Mediator делает систему слабо связанной, избавляя объекты от необходимости ссылаться друг на друга, что позволяет изменять взаимодействие между ними независимо.
7 |
8 | Например, у нас есть посредник между заводом производства хлебобулочных изделий, фермером и магазином сбыта. Посредник избавляет фермера от взаимодействия с заводом, который использует его сырье, а завод от взаимодействия с магазином, в который поступает продукция для сбыта.
9 |
10 | Требуется для реализации:
11 |
12 | 1. Интерфейс Mediator - посредник описывающий организацию процесса по обмену информацией между объектами типа Colleague;
13 | 2. Класс ConcreteMediator, реализующий интерфейс Mediator;
14 | 3. Базовый абстрактный класс Colleague - коллега описывающий организацию процесса взаимодействия объектов-коллег с объектом типа Mediator;
15 | 4. Класс ConcreteColleague, реализующий интерфейс Colleague. Каждый объект-коллега знает только об объекте-медиаторе. Все объекты-коллеги обмениваются информацией только через посредника.
16 |
17 | [!] В описании паттерна применяются общие понятия, такие как Класс, Объект, Абстрактный класс. Применимо к языку Go, это Пользовательский Тип, Значение этого Типа и Интерфейс. Также в языке Go за место общепринятого наследования используется агрегирование и встраивание.
18 |
19 | ## -~- THE END -~-
--------------------------------------------------------------------------------
/Behavioral/Mediator/mediator.go:
--------------------------------------------------------------------------------
1 | // Package mediator is an example of the Mediator Pattern.
2 | package mediator
3 |
4 | // Mediator provides a mediator interface.
5 | type Mediator interface {
6 | Notify(msg string)
7 | }
8 |
9 | // Тип ConcreteMediator, реализует посредника
10 | type ConcreteMediator struct {
11 | *Farmer
12 | *Cannery
13 | *Shop
14 | }
15 |
16 | // Notify implementation.
17 | func (m *ConcreteMediator) Notify(msg string) {
18 | if msg == "Farmer: Tomato complete..." {
19 | m.Cannery.AddMoney(-15000.00)
20 | m.Farmer.AddMoney(15000.00)
21 | m.Cannery.MakeKetchup(m.Farmer.GetTomato())
22 | } else if msg == "Cannery: Ketchup complete..." {
23 | m.Shop.AddMoney(-30000.00)
24 | m.Cannery.AddMoney(30000.00)
25 | m.Shop.SellKetchup(m.Cannery.GetKetchup())
26 | }
27 | }
28 |
29 | // СonnectСolleagues connects all colleagues.
30 | func СonnectСolleagues(farmer *Farmer, cannery *Cannery, shop *Shop) {
31 | mediator := &ConcreteMediator{
32 | Farmer: farmer,
33 | Cannery: cannery,
34 | Shop: shop,
35 | }
36 |
37 | mediator.Farmer.SetMediator(mediator)
38 | mediator.Cannery.SetMediator(mediator)
39 | mediator.Shop.SetMediator(mediator)
40 | }
41 |
42 | // Farmer implements a Farmer colleague
43 | type Farmer struct {
44 | mediator Mediator
45 | tomato int
46 | money float64
47 | }
48 |
49 | // SetMediator sets mediator.
50 | func (f *Farmer) SetMediator(mediator Mediator) {
51 | f.mediator = mediator
52 | }
53 |
54 | // AddMoney adds money.
55 | func (f *Farmer) AddMoney(m float64) {
56 | f.money += m
57 | }
58 |
59 | // GrowTomato implementation.
60 | func (f *Farmer) GrowTomato(tomato int) {
61 | f.tomato = tomato
62 | f.money -= 7500.00
63 | f.mediator.Notify("Farmer: Tomato complete...")
64 | }
65 |
66 | // GetTomato returns tomatos.
67 | func (f *Farmer) GetTomato() int {
68 | return f.tomato
69 | }
70 |
71 | // Cannery implements a Cannery colleague.
72 | type Cannery struct {
73 | mediator Mediator
74 | ketchup int
75 | money float64
76 | }
77 |
78 | // SetMediator sets mediator.
79 | func (c *Cannery) SetMediator(mediator Mediator) {
80 | c.mediator = mediator
81 | }
82 |
83 | // AddMoney adds money.
84 | func (c *Cannery) AddMoney(m float64) {
85 | c.money += m
86 | }
87 |
88 | // MakeKetchup implementation.
89 | func (c *Cannery) MakeKetchup(tomato int) {
90 | c.ketchup = tomato
91 | c.mediator.Notify("Cannery: Ketchup complete...")
92 | }
93 |
94 | // GetKetchup returns ketchup.
95 | func (c *Cannery) GetKetchup() int {
96 | return c.ketchup
97 | }
98 |
99 | // Shop implements a Shop colleague.
100 | type Shop struct {
101 | mediator Mediator
102 | money float64
103 | }
104 |
105 | // SetMediator sets mediator.
106 | func (s *Shop) SetMediator(mediator Mediator) {
107 | s.mediator = mediator
108 | }
109 |
110 | // AddMoney adds money.
111 | func (s *Shop) AddMoney(m float64) {
112 | s.money += m
113 | }
114 |
115 | // SellKetchup converts ketchup to money.
116 | func (s *Shop) SellKetchup(ketchup int) {
117 | s.money = float64(ketchup) * 54.75
118 | }
119 |
120 | // GetMoney returns money.
121 | func (s *Shop) GetMoney() float64 {
122 | return s.money
123 | }
124 |
--------------------------------------------------------------------------------
/Behavioral/Mediator/mediator_test.go:
--------------------------------------------------------------------------------
1 | package mediator
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestMediator(t *testing.T) {
8 |
9 | farmer := new(Farmer)
10 | cannery := new(Cannery)
11 | shop := new(Shop)
12 |
13 | farmer.AddMoney(7500.00)
14 | cannery.AddMoney(15000.00)
15 | shop.AddMoney(30000.00)
16 |
17 | СonnectСolleagues(farmer, cannery, shop)
18 |
19 | // A farmer grows a 1000kg tomato
20 | // and informs the mediator about the completion of his work.
21 | // Next, the mediator sends the tomatoes to the cannery.
22 | // After the cannery produces 1000 packs of ketchup,
23 | // he informs the mediator about his delivery to the store.
24 | farmer.GrowTomato(1000)
25 |
26 | expect := float64(54750)
27 | result := shop.GetMoney()
28 |
29 | if result != expect {
30 | t.Errorf("Expect result to equal %f, but %f.\n", expect, result)
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Behavioral/Memento/README.md:
--------------------------------------------------------------------------------
1 |
2 | ## Хранитель (Memento)
3 |
4 | Паттерн Memento относится к поведенческим паттернам уровня объекта.
5 |
6 | Паттерн Memento получает и сохраняет за пределами объекта его внутреннее состояние так, чтобы позже можно было восстановить объект в таком же состоянии. Если клиенту в дальнейшем нужно "откатить" состояние исходного объекта, он передает Memento обратно в исходный объект для его восстановления.
7 |
8 | Паттерн оперирует тремя объектами:
9 |
10 | 1. Хозяин состояния (Originator);
11 | 2. Хранитель (Memento) - Хранит в себе состояние объекта-хозяина класса Originator;
12 | 3. Смотритель (Caretaker) - Отвечает за сохранность объекта-хранителя класса Memento.
13 |
14 | Требуется для реализации:
15 |
16 | 1. Класс Originator, у которого есть какое-то меняющиеся состояние, а так же он может создавать и принимать хранителей (Memento) своего состояния;
17 | 2. Класс Memento, реализует хранилище для состояния Originator;
18 | 3. Класс Caretaker, получает и хранит объект-хранитель (Memento), пока он не понадобится хозяину.
19 |
20 | [!] В описании паттерна применяются общие понятия, такие как Класс, Объект, Абстрактный класс. Применимо к языку Go, это Пользовательский Тип, Значение этого Типа и Интерфейс. Также в языке Go за место общепринятого наследования используется агрегирование и встраивание.
21 |
22 | ## -~- THE END -~-
--------------------------------------------------------------------------------
/Behavioral/Memento/memento.go:
--------------------------------------------------------------------------------
1 | // Package memento is an example of the Memento Pattern.
2 | package memento
3 |
4 | // Originator implements a state master.
5 | type Originator struct {
6 | State string
7 | }
8 |
9 | // CreateMemento returns state storage.
10 | func (o *Originator) CreateMemento() *Memento {
11 | return &Memento{state: o.State}
12 | }
13 |
14 | // SetMemento sets old state.
15 | func (o *Originator) SetMemento(memento *Memento) {
16 | o.State = memento.GetState()
17 | }
18 |
19 | // Memento implements storage for the state of Originator
20 | type Memento struct {
21 | state string
22 | }
23 |
24 | // GetState returns state.
25 | func (m *Memento) GetState() string {
26 | return m.state
27 | }
28 |
29 | // Caretaker keeps Memento until it is needed by Originator.
30 | type Caretaker struct {
31 | Memento *Memento
32 | }
33 |
--------------------------------------------------------------------------------
/Behavioral/Memento/memento_test.go:
--------------------------------------------------------------------------------
1 | package memento
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestMomento(t *testing.T) {
8 |
9 | originator := new(Originator)
10 | caretaker := new(Caretaker)
11 |
12 | originator.State = "On"
13 |
14 | caretaker.Memento = originator.CreateMemento()
15 |
16 | originator.State = "Off"
17 |
18 | originator.SetMemento(caretaker.Memento)
19 |
20 | if originator.State != "On" {
21 | t.Errorf("Expect State to %s, but %s", originator.State, "On")
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Behavioral/Observer/README.md:
--------------------------------------------------------------------------------
1 |
2 | ## Наблюдатель (Observer)
3 |
4 | Паттерн Observer относится к поведенческим паттернам уровня объекта.
5 |
6 | Паттерн Observer определяет зависимость "один-ко-многим" между объектами так, что при изменении состояния одного объекта все зависящие от него объекты уведомляются об этом и обновляются автоматически.
7 |
8 | Основные участиники паттерна это Издатели (Subject) и Подписчики (Observer).
9 |
10 | Имеется два способа получения уведомлений от издателя:
11 |
12 | 1. Метод вытягивания: После получения уведомления от издателя, подписчик должен пойти к издателю и забрать (вытянуть) данные самостоятельно.
13 | 2. Метод проталкивания: Издатель не уведомляет подписчика об обновлениях данных, а самостоятельно доставляет (проталкивает) данные подписчику.
14 |
15 | Требуется для реализации:
16 |
17 | 1. Абстрактный класс Subject, определяющий интерфейс Издателя;
18 | 2. Класс ConcreteSubject, реализует интерфейс Subject;
19 | 3. Абстрактный класс Observer, определяющий общий функционал Подписчиков;
20 | 4. Класс ConcreteObserver, реализует Подписчика;
21 |
22 | [!] В описании паттерна применяются общие понятия, такие как Класс, Объект, Абстрактный класс. Применимо к языку Go, это Пользовательский Тип, Значение этого Типа и Интерфейс. Также в языке Go за место общепринятого наследования используется агрегирование и встраивание.
23 |
24 | ## -~- THE END -~-
--------------------------------------------------------------------------------
/Behavioral/Observer/observer.go:
--------------------------------------------------------------------------------
1 | // Package observer is an example of the Observer Pattern.
2 | // Push model.
3 | package observer
4 |
5 | // Publisher interface.
6 | type Publisher interface {
7 | Attach(observer Observer)
8 | SetState(state string)
9 | Notify()
10 | }
11 |
12 | // Observer provides a subscriber interface.
13 | type Observer interface {
14 | Update(state string)
15 | }
16 |
17 | // ConcretePublisher implements the Publisher interface.
18 | type ConcretePublisher struct {
19 | observers []Observer
20 | state string
21 | }
22 |
23 | // NewPublisher is the Publisher constructor.
24 | func NewPublisher() Publisher {
25 | return &ConcretePublisher{}
26 | }
27 |
28 | // Attach a Observer
29 | func (s *ConcretePublisher) Attach(observer Observer) {
30 | s.observers = append(s.observers, observer)
31 | }
32 |
33 | // SetState sets new state
34 | func (s *ConcretePublisher) SetState(state string) {
35 | s.state = state
36 | }
37 |
38 | // Notify sends notifications to subscribers.
39 | // Push model.
40 | func (s *ConcretePublisher) Notify() {
41 | for _, observer := range s.observers {
42 | observer.Update(s.state)
43 | }
44 | }
45 |
46 | // ConcreteObserver implements the Observer interface.
47 | type ConcreteObserver struct {
48 | state string
49 | }
50 |
51 | // Update set new state
52 | func (s *ConcreteObserver) Update(state string) {
53 | s.state = state
54 | }
55 |
--------------------------------------------------------------------------------
/Behavioral/Observer/observer_test.go:
--------------------------------------------------------------------------------
1 | package observer
2 |
3 | func ExampleObserver() {
4 |
5 | publisher := NewPublisher()
6 |
7 | publisher.Attach(&ConcreteObserver{})
8 | publisher.Attach(&ConcreteObserver{})
9 | publisher.Attach(&ConcreteObserver{})
10 |
11 | publisher.SetState("New State...")
12 |
13 | publisher.Notify()
14 | }
15 |
--------------------------------------------------------------------------------
/Behavioral/README.md:
--------------------------------------------------------------------------------
1 |
2 | ## Поведенческие паттерны (Behavioral)
3 |
4 | Поведенческие паттерны делятся на два типа:
5 |
6 | 1. Паттерны уровня класса
7 | 2. Паттерны уровня объекта.
8 |
9 | Паттерны уровня класса описывают взаимодействия между классами и их подклассами. Такие отношения выражаются путем наследования и реализации классов. Тут базовый класс определяет интерфейс, а подклассы - реализацию.
10 |
11 | Паттерны уровня объекта описывают взаимодействия между объектами. Такие отношения выражаются связями - ассоциацией, агрегацией и композицией. Тут структуры строятся путем объединения объектов некоторых классов.
12 |
13 | Ассоциация - отношение, когда объекты двух классов могут ссылаться один на другой. Например, свойство класса содержит экземпляр другого класса.
14 |
15 | Агрегация – частная форма ассоциации. Агрегация применяется, когда один объект должен быть контейнером для других объектов и время существования этих объектов никак не зависит от времени существования объекта контейнера. Вообщем, если контейнер будет уничтожен, то входящие в него объекты не пострадают. Например, мы создали объект, а потом передали его в объект контейнер, каким-либо образом, можно в метод объекта контейнера передать или присвоить сразу свойству контейнера извне. Значит при удалении контейнера мы ни как не затронем наш созданный объект, который может взаимодействовать и с другими контейнерами.
16 |
17 | Композиция – Тоже самое, что и агрегация, но составные объекты не могут существовать отдельно от объекта контейнера и если контейнер будет уничтожен, то всё его содержимое будет уничтожено тоже. Например, мы создали объект в методе объекта контейнера и присвоили его свойству объекта контейнера. Из вне, о нашем созданном объекте никто не знает, значит, при удалении контейнера, созданный объект убудет удален так же, т.к. на него нет ссылки извне.
18 |
19 | К паттернам уровня класса относится только «Шаблонный метод».
20 |
21 | Поведенческие паттерны описывают взаимодействие объектов и классов между собой и пытаются добиться наименьшей степени связанности компонентов системы друг с другом делая систему более гибкой.
22 |
23 | * [Цепочка ответственности (Chain Of Responsibility)](ChainOfResponsibility)
24 | * [Команда (Command)](Command)
25 | * [Итератор (Iterator)](Iterator)
26 | * [Посредник (Mediator)](Mediator)
27 | * [Хранитель (Memento)](Memento)
28 | * [Наблюдатель (Observer)](Observer)
29 | * [Состояние (State)](State)
30 | * [Стратегия (Strategy)](Strategy)
31 | * [Шаблонный метод (Template Method)](TemplateMethod)
32 | * [Посетитель (Visitor)](Visitor)
33 |
34 | ## -~- THE END -~-
--------------------------------------------------------------------------------
/Behavioral/State/README.md:
--------------------------------------------------------------------------------
1 |
2 | ## Состояние (State)
3 |
4 | Паттерн State относится к поведенческим паттернам уровня объекта.
5 |
6 | Паттерн State позволяет объекту изменять свое поведение в зависимости от внутреннего состояния и является объектно-ориентированной реализацией конечного автомата. Поведение объекта изменяется настолько, что создается впечатление, будто изменился класс объекта.
7 |
8 | Паттерн должен применяться:
9 |
10 | - когда поведение объекта зависит от его состояния
11 | - поведение объекта должно изменяться во время выполнения программы
12 | - состояний достаточно много и использовать для этого условные операторы, разбросанные по коду, достаточно затруднительно
13 |
14 | Требуется для реализации:
15 |
16 | 1. Класс Context, представляет собой объектно-ориентированное представление конечного автомата;
17 | 2. Абстрактный класс State, определяющий интерфейс различных состояний;
18 | 3. Класс ConcreteStateA реализует одно из поведений, ассоциированное с определенным состоянием;
19 | 4. Класс ConcreteStateB реализует одно из поведений, ассоциированное с определенным состоянием.
20 |
21 | [!] В описании паттерна применяются общие понятия, такие как Класс, Объект, Абстрактный класс. Применимо к языку Go, это Пользовательский Тип, Значение этого Типа и Интерфейс. Также в языке Go вместо наследования используется композиция.
22 |
23 | ## -~- THE END -~-
24 |
25 |
--------------------------------------------------------------------------------
/Behavioral/State/state.go:
--------------------------------------------------------------------------------
1 | // Package state is an example of the State Pattern.
2 | package state
3 |
4 | // MobileAlertStater provides a common interface for various states.
5 | type MobileAlertStater interface {
6 | Alert() string
7 | }
8 |
9 | // MobileAlert implements an alert depending on its state.
10 | type MobileAlert struct {
11 | state MobileAlertStater
12 | }
13 |
14 | // Alert returns a alert string
15 | func (a *MobileAlert) Alert() string {
16 | return a.state.Alert()
17 | }
18 |
19 | // SetState changes state
20 | func (a *MobileAlert) SetState(state MobileAlertStater) {
21 | a.state = state
22 | }
23 |
24 | // NewMobileAlert is the MobileAlert constructor.
25 | func NewMobileAlert() *MobileAlert {
26 | return &MobileAlert{state: &MobileAlertVibration{}}
27 | }
28 |
29 | // MobileAlertVibration implements vibration alert
30 | type MobileAlertVibration struct {
31 | }
32 |
33 | // Alert returns a alert string
34 | func (a *MobileAlertVibration) Alert() string {
35 | return "Vrrr... Brrr... Vrrr..."
36 | }
37 |
38 | // MobileAlertSong implements beep alert
39 | type MobileAlertSong struct {
40 | }
41 |
42 | // Alert returns a alert string
43 | func (a *MobileAlertSong) Alert() string {
44 | return "Белые розы, Белые розы. Беззащитны шипы..."
45 | }
46 |
--------------------------------------------------------------------------------
/Behavioral/State/state_test.go:
--------------------------------------------------------------------------------
1 | package state
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestState(t *testing.T) {
8 |
9 | expect := "Vrrr... Brrr... Vrrr..." +
10 | "Vrrr... Brrr... Vrrr..." +
11 | "Белые розы, Белые розы. Беззащитны шипы..."
12 |
13 | mobile := NewMobileAlert()
14 |
15 | result := mobile.Alert()
16 | result += mobile.Alert()
17 |
18 | mobile.SetState(&MobileAlertSong{})
19 |
20 | result += mobile.Alert()
21 |
22 | if result != expect {
23 | t.Errorf("Expect result to equal %s, but %s.\n", expect, result)
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Behavioral/Strategy/README.md:
--------------------------------------------------------------------------------
1 |
2 | ## Стратегия (Strategy)
3 |
4 | Паттерн Strategy относится к поведенческим паттернам уровня объекта.
5 |
6 | Паттерн Strategy определяет набор алгоритмов схожих по роду деятельности, инкапсулирует их в отдельный класс и делает их подменяемыми. Паттерн Strategy позволяет подменять алгоритмы без участия клиентов, которые используют эти алгоритмы.
7 |
8 | Требуется для реализации:
9 |
10 | 1. Класс Context, представляющий собой контекст выполнения той или иной стратегии;
11 | 2. Абстрактный класс Strategy, определяющий интерфейс различных стратегий;
12 | 3. Класс ConcreteStrategyA, реализует одну из стратегий представляющую собой алгоритмы, направленные на достижение определенной цели;
13 | 4. Класс ConcreteStrategyB, реализует одно из стратегий представляющую собой алгоритмы, направленные на достижение определенной цели.
14 |
15 | [!] В описании паттерна применяются общие понятия, такие как Класс, Объект, Абстрактный класс. Применимо к языку Go, это Пользовательский Тип, Значение этого Типа и Интерфейс. Также в языке Go за место общепринятого наследования используется агрегирование и встраивание.
16 |
17 | ## -~- THE END -~-
18 |
--------------------------------------------------------------------------------
/Behavioral/Strategy/strategy.go:
--------------------------------------------------------------------------------
1 | // Package strategy is an example of the Strategy Pattern.
2 | package strategy
3 |
4 | // StrategySort provides an interface for sort algorithms.
5 | type StrategySort interface {
6 | Sort([]int)
7 | }
8 |
9 | // BubbleSort implements bubble sort algorithm.
10 | type BubbleSort struct {
11 | }
12 |
13 | // Sort sorts data.
14 | func (s *BubbleSort) Sort(a []int) {
15 | size := len(a)
16 | if size < 2 {
17 | return
18 | }
19 | for i := 0; i < size; i++ {
20 | for j := size - 1; j >= i+1; j-- {
21 | if a[j] < a[j-1] {
22 | a[j], a[j-1] = a[j-1], a[j]
23 | }
24 | }
25 | }
26 | }
27 |
28 | // InsertionSort implements insertion sort algorithm.
29 | type InsertionSort struct {
30 | }
31 |
32 | // Sort sorts data.
33 | func (s *InsertionSort) Sort(a []int) {
34 | size := len(a)
35 | if size < 2 {
36 | return
37 | }
38 | for i := 1; i < size; i++ {
39 | var j int
40 | var buff = a[i]
41 | for j = i - 1; j >= 0; j-- {
42 | if a[j] < buff {
43 | break
44 | }
45 | a[j+1] = a[j]
46 | }
47 | a[j+1] = buff
48 | }
49 | }
50 |
51 | // Context provides a context for execution of a strategy.
52 | type Context struct {
53 | strategy StrategySort
54 | }
55 |
56 | // Algorithm replaces strategies.
57 | func (c *Context) Algorithm(a StrategySort) {
58 | c.strategy = a
59 | }
60 |
61 | // Sort sorts data according to the chosen strategy.
62 | func (c *Context) Sort(s []int) {
63 | c.strategy.Sort(s)
64 | }
65 |
--------------------------------------------------------------------------------
/Behavioral/Strategy/strategy_test.go:
--------------------------------------------------------------------------------
1 | package strategy
2 |
3 | import (
4 | "strconv"
5 | "testing"
6 | )
7 |
8 | func TestStrategy(t *testing.T) {
9 |
10 | data1 := []int{8, 2, 6, 7, 1, 3, 9, 5, 4}
11 | data2 := []int{8, 2, 6, 7, 1, 3, 9, 5, 4}
12 |
13 | ctx := new(Context)
14 |
15 | ctx.Algorithm(&BubbleSort{})
16 |
17 | ctx.Sort(data1)
18 |
19 | ctx.Algorithm(&InsertionSort{})
20 |
21 | ctx.Sort(data2)
22 |
23 | expect := "1,2,3,4,5,6,7,8,9,"
24 |
25 | var result1 string
26 | for _, val := range data1 {
27 | result1 += strconv.Itoa(val) + ","
28 | }
29 |
30 | if result1 != expect {
31 | t.Errorf("Expect result1 to equal %s, but %s.\n", expect, result1)
32 | }
33 |
34 | var result2 string
35 | for _, val := range data2 {
36 | result2 += strconv.Itoa(val) + ","
37 | }
38 |
39 | if result2 != expect {
40 | t.Errorf("Expect result2 to equal %s, but %s.\n", expect, result2)
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Behavioral/TemplateMethod/README.md:
--------------------------------------------------------------------------------
1 |
2 | ## Шаблонный метод (Template Method)
3 |
4 | Паттерн Template Method относится к поведенческим паттернам уровня класса.
5 |
6 | Паттерн Template Method формирует структуру алгоритма и позволяет в производных классах реализовать, перекрыть или переопределить определенные шаги алгоритма, не изменяя структуру алгоритма в целом.
7 |
8 | Проектировщик решает, какие шаги алгоритма являются неизменными, а какие изменяемыми. Абстрактный базовый класс реализует стандартные неизменяемые шаги алгоритма и может предоставлять реализацию по умолчанию для изменяемых шагов. Изменяемые шаги могут предоставляться клиентом компонента в конкретных производных классах.
9 |
10 | Требуется для реализации:
11 |
12 | 1. Абстрактный класс AbstractClass, реализующий Template Method, который описывает порядок действий;
13 | 2. Класс ConcreteClass, реализующий изменяемые действия.
14 |
15 | [!] В описании паттерна применяются общие понятия, такие как Класс, Объект, Абстрактный класс. Применимо к языку Go, это Пользовательский Тип, Значение этого Типа и Интерфейс. Также в языке Go за место общепринятого наследования используется агрегирование и встраивание.
16 |
17 | Т.к. в Go нет понятия "Абстрактный Класс" и знакомого нам полиморфизма на наследовании, следует использовать встравивания общего для ConcreteClass типа с реализацией Template Method.
18 |
19 | ## -~- THE END -~-
20 |
--------------------------------------------------------------------------------
/Behavioral/TemplateMethod/template_method.go:
--------------------------------------------------------------------------------
1 | // Package template_method is an example of the Template Method Pattern.
2 | // In fact, this pattern is based on Abstract Class and Polymorphism.
3 | // But there’s nothing like that in Go, so the composition will be applied.
4 | package template_method
5 |
6 | // QuotesInterface provides an interface for setting different quotes.
7 | type QuotesInterface interface {
8 | Open() string
9 | Close() string
10 | }
11 |
12 | // Quotes implements a Template Method.
13 | type Quotes struct {
14 | QuotesInterface
15 | }
16 |
17 | // Quotes is the Template Method.
18 | func (q *Quotes) Quotes(str string) string {
19 | return q.Open() + str + q.Close()
20 | }
21 |
22 | // NewQuotes is the Quotes constructor.
23 | func NewQuotes(qt QuotesInterface) *Quotes {
24 | return &Quotes{qt}
25 | }
26 |
27 | // FrenchQuotes implements wrapping the string in French quotes.
28 | type FrenchQuotes struct {
29 | }
30 |
31 | // Open sets opening quotes.
32 | func (q *FrenchQuotes) Open() string {
33 | return "«"
34 | }
35 |
36 | // Close sets closing quotes.
37 | func (q *FrenchQuotes) Close() string {
38 | return "»"
39 | }
40 |
41 | // GermanQuotes implements wrapping the string in German quotes.
42 | type GermanQuotes struct {
43 | }
44 |
45 | // Open sets opening quotes.
46 | func (q *GermanQuotes) Open() string {
47 | return "„"
48 | }
49 |
50 | // Close sets closing quotes.
51 | func (q *GermanQuotes) Close() string {
52 | return "“"
53 | }
54 |
--------------------------------------------------------------------------------
/Behavioral/TemplateMethod/template_method_test.go:
--------------------------------------------------------------------------------
1 | package template_method
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestTemplateMethod(t *testing.T) {
8 |
9 | expect := "«Test String»"
10 |
11 | qt := NewQuotes(&FrenchQuotes{})
12 |
13 | result := qt.Quotes("Test String")
14 |
15 | if result != expect {
16 | t.Errorf("Expect result to equal %s, but %s.\n", expect, result)
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Behavioral/Visitor/README.md:
--------------------------------------------------------------------------------
1 |
2 | ## Посетитель (Visitor)
3 |
4 | Паттерн Visitor относится к поведенческим паттернам уровня объекта.
5 |
6 | Паттерн Visitor позволяет обойти набор элементов (объектов) с разнородными интерфейсами, а также позволяет добавить новый метод в класс объекта, при этом, не изменяя сам класс этого объекта.
7 |
8 | Требуется для реализации:
9 |
10 | 1. Абстрактный класс Visitor, описывающий интерфейс визитера;
11 | 2. Класс ConcreteVisitor, реализующий конкретного визитера. Реализует методы для обхода конкретного элемента;
12 | 3. Класс ObjectStructure, реализующий структуру(коллекцию), в которой хранятся элементы для обхода;
13 | 4. Абстрактный класс Element, реализующий интерфейс элементов структуры;
14 | 5. Класс ElementA, реализующий элемент структуры;
15 | 6. Класс ElementB, реализующий элемент структуры.
16 |
17 | [!] В описании паттерна применяются общие понятия, такие как Класс, Объект, Абстрактный класс. Применимо к языку Go, это Пользовательский Тип, Значение этого Типа и Интерфейс. Также в языке Go за место общепринятого наследования используется агрегирование и встраивание.
18 |
19 | ## -~- THE END -~-
20 |
--------------------------------------------------------------------------------
/Behavioral/Visitor/visitor.go:
--------------------------------------------------------------------------------
1 | // Package visitor is an example of the Visitor Pattern.
2 | package visitor
3 |
4 | // Visitor provides a visitor interface.
5 | type Visitor interface {
6 | VisitSushiBar(p *SushiBar) string
7 | VisitPizzeria(p *Pizzeria) string
8 | VisitBurgerBar(p *BurgerBar) string
9 | }
10 |
11 | // Place provides an interface for place that the visitor should visit.
12 | type Place interface {
13 | Accept(v Visitor) string
14 | }
15 |
16 | // People implements the Visitor interface.
17 | type People struct {
18 | }
19 |
20 | // VisitSushiBar implements visit to SushiBar.
21 | func (v *People) VisitSushiBar(p *SushiBar) string {
22 | return p.BuySushi()
23 | }
24 |
25 | // VisitPizzeria implements visit to Pizzeria.
26 | func (v *People) VisitPizzeria(p *Pizzeria) string {
27 | return p.BuyPizza()
28 | }
29 |
30 | // VisitBurgerBar implements visit to BurgerBar.
31 | func (v *People) VisitBurgerBar(p *BurgerBar) string {
32 | return p.BuyBurger()
33 | }
34 |
35 | // City implements a collection of places to visit.
36 | type City struct {
37 | places []Place
38 | }
39 |
40 | // Add appends Place to the collection.
41 | func (c *City) Add(p Place) {
42 | c.places = append(c.places, p)
43 | }
44 |
45 | // Accept implements a visit to all places in the city.
46 | func (c *City) Accept(v Visitor) string {
47 | var result string
48 | for _, p := range c.places {
49 | result += p.Accept(v)
50 | }
51 | return result
52 | }
53 |
54 | // SushiBar implements the Place interface.
55 | type SushiBar struct {
56 | }
57 |
58 | // Accept implementation.
59 | func (s *SushiBar) Accept(v Visitor) string {
60 | return v.VisitSushiBar(s)
61 | }
62 |
63 | // BuySushi implementation.
64 | func (s *SushiBar) BuySushi() string {
65 | return "Buy sushi..."
66 | }
67 |
68 | // Pizzeria implements the Place interface.
69 | type Pizzeria struct {
70 | }
71 |
72 | // Accept implementation.
73 | func (p *Pizzeria) Accept(v Visitor) string {
74 | return v.VisitPizzeria(p)
75 | }
76 |
77 | // BuyPizza implementation.
78 | func (p *Pizzeria) BuyPizza() string {
79 | return "Buy pizza..."
80 | }
81 |
82 | // BurgerBar implements the Place interface.
83 | type BurgerBar struct {
84 | }
85 |
86 | // Accept implementation.
87 | func (b *BurgerBar) Accept(v Visitor) string {
88 | return v.VisitBurgerBar(b)
89 | }
90 |
91 | // BuyBurger implementation.
92 | func (b *BurgerBar) BuyBurger() string {
93 | return "Buy burger..."
94 | }
95 |
--------------------------------------------------------------------------------
/Behavioral/Visitor/visitor_test.go:
--------------------------------------------------------------------------------
1 | package visitor
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestVisitor(t *testing.T) {
8 |
9 | expect := "Buy sushi...Buy pizza...Buy burger..."
10 |
11 | city := new(City)
12 |
13 | city.Add(&SushiBar{})
14 | city.Add(&Pizzeria{})
15 | city.Add(&BurgerBar{})
16 |
17 | result := city.Accept(&People{})
18 |
19 | if result != expect {
20 | t.Errorf("Expect result to equal %s, but %s.\n", expect, result)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Creational/AbstractFactory/README.md:
--------------------------------------------------------------------------------
1 |
2 | ## Абстрактная фабрика (Abstract Factory)
3 |
4 | Паттерн Abstract Factory относится к порождающим паттернам уровня объекта.
5 |
6 | Паттерн Abstract Factory предоставляет общий интерфейс для создания семейства взаимосвязанных объектов. Это позволяет отделить функциональность системы от внутренней реализации каждого класса, а обращение к этим классам становится возможным через абстрактные интерфейсы.
7 |
8 | В общем виде абстрактная фабрика выглядит следующим образом. Для каждого из семейств объектов, создается конкретная фабрика (наследник абстрактной), посредством которой создаются продукты этого семейства.
9 |
10 | Пример: Есть две фабрики по производству газировки, Кока-Кола и Пепси. Эти фабрики выпускают семейство продуктов (объектов) - бутылка, крышка, этикетка, жидкость. Каждая из этих фабрик выпускает продукты, которые взаимодействуют между собой и не могут жить отдельно друг от друга. Фабрика Кока-Кола не может поставлять клиентам пустые бутылки.
11 |
12 | Что бы реализовать простое создание семейства объектов, должен быть интерфейс, по которому работает фабрика, так же фабрика должна выпускать продукты с определенным интерфейсом. Например, бутылки обеих компаний обладают одним интерфейсом - у них есть горлышко через которое они наполняются жидкостью, так же мы можем узнать объем бутылок. Дальше бутылки могут отличаться по форме, объему или материалу, нас это не касается, нам нужно только знать, куда наливать жидкость, а так же, сколько этой жидкости нужно.
13 |
14 | Требуется для реализации:
15 |
16 | 1. Класс абстрактной фабрики AbstractFactory, описывающий общий интерфейс фабрики, от которой будет наследоваться каждая конкретная фабрика;
17 | 2. Класс абстрактного продукта AbstractProduct, описывающий общий интерфейс продукта, от которого будет наследоваться каждый конкретный продукт;
18 | 3. Класс конкретной фабрики Factory;
19 | 4. Класс конкретного продукта ProductA.
20 | 5. Класс конкретного продукта ProductB.
21 |
22 | Подведем итог.
23 |
24 | Абстрактная фабрика представляет собой базовый класс, описывающий интерфейс конкретных фабрик, создающих продукты. Производные от него классы конкретных фабрик, должны реализовать этот интерфейс.
25 |
26 | Также абстрактная фабрика должна описывать абстрактные продукты, которые она производит, что бы конкретные фабрики производили продукты с нужными интерфейсами.
27 |
28 | [!] В описании паттерна применяются общие понятия, такие как Класс, Объект, Абстрактный класс. Применимо к языку Go, это Пользовательский Тип, Значение этого Типа и Интерфейс. Также в языке Go за место общепринятого наследования используется агрегирование и встраивание.
29 |
30 | ## -~- THE END -~-
--------------------------------------------------------------------------------
/Creational/AbstractFactory/abstract_factory.go:
--------------------------------------------------------------------------------
1 | // Package abstract_factory is an example of the Abstract Factory Pattern.
2 | package abstract_factory
3 |
4 | // AbstractFactory provides an interface for creating families of related objects.
5 | type AbstractFactory interface {
6 | CreateWater(volume float64) AbstractWater
7 | CreateBottle(volume float64) AbstractBottle
8 | }
9 |
10 | // AbstractWater provides a water interface.
11 | type AbstractWater interface {
12 | GetVolume() float64
13 | }
14 |
15 | // AbstractBottle provides a bottle interface.
16 | type AbstractBottle interface {
17 | PourWater(water AbstractWater) // Bottle interacts with a water.
18 | GetBottleVolume() float64
19 | GetWaterVolume() float64
20 | }
21 |
22 | // CocaColaFactory implements AbstractFactory interface.
23 | type CocaColaFactory struct {
24 | }
25 |
26 | // NewCocaColaFactory is the CocaColaFactory constructor.
27 | func NewCocaColaFactory() AbstractFactory {
28 | return &CocaColaFactory{}
29 | }
30 |
31 | // CreateWater implementation.
32 | func (f *CocaColaFactory) CreateWater(volume float64) AbstractWater {
33 | return &CocaColaWater{volume: volume}
34 | }
35 |
36 | // CreateBottle implementation.
37 | func (f *CocaColaFactory) CreateBottle(volume float64) AbstractBottle {
38 | return &CocaColaBottle{volume: volume}
39 | }
40 |
41 | // CocaColaWater implements AbstractWater.
42 | type CocaColaWater struct {
43 | volume float64 // Volume of drink.
44 | }
45 |
46 | // GetVolume returns volume of drink.
47 | func (w *CocaColaWater) GetVolume() float64 {
48 | return w.volume
49 | }
50 |
51 | // CocaColaBottle implements AbstractBottle.
52 | type CocaColaBottle struct {
53 | water AbstractWater // Bottle must contain a drink.
54 | volume float64 // Volume of bottle.
55 | }
56 |
57 | // PourWater pours water into a bottle.
58 | func (b *CocaColaBottle) PourWater(water AbstractWater) {
59 | b.water = water
60 | }
61 |
62 | // GetBottleVolume returns volume of bottle.
63 | func (b *CocaColaBottle) GetBottleVolume() float64 {
64 | return b.volume
65 | }
66 |
67 | // GetWaterVolume returns volume of water.
68 | func (b *CocaColaBottle) GetWaterVolume() float64 {
69 | return b.water.GetVolume()
70 | }
71 |
--------------------------------------------------------------------------------
/Creational/AbstractFactory/abstract_factory_test.go:
--------------------------------------------------------------------------------
1 | package abstract_factory
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestAbstractFactory(t *testing.T) {
8 |
9 | cocacolaFactory := NewCocaColaFactory()
10 |
11 | cocacolaWater := cocacolaFactory.CreateWater(2.5)
12 | cocacolaBottle := cocacolaFactory.CreateBottle(2.5)
13 |
14 | cocacolaBottle.PourWater(cocacolaWater)
15 |
16 | if cocacolaBottle.GetWaterVolume() != cocacolaBottle.GetBottleVolume() {
17 | t.Errorf("Expect volume to %.1fL, but %.1fL", cocacolaBottle.GetWaterVolume(), cocacolaBottle.GetBottleVolume())
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Creational/Builder/README.md:
--------------------------------------------------------------------------------
1 |
2 | ## Строитель (Builder)
3 |
4 | Паттерн Builder относится к порождающим паттернам уровня объекта.
5 |
6 | Паттерн Builder определяет процесс поэтапного построения сложного продукта. После того как будет построена последняя его часть, продукт можно использовать.
7 |
8 | В примере паттерна Abstract Factory приводился пример двух фабрик Кока-Кола и Перси. Возьмем одну фабрику, она производит сложный продукт, состоящий из 4 частей (крышка, бутылка, этикетка, напиток), которые должны быть применены в нужном порядке. Нельзя вначале взять крышку, бутылку, завинтить крышку, а потом пытаться налить туда напиток. Для реализации объекта, бутылки Кока-Колы, которая поставляется клиенту, нам нужен паттерн Builder.
9 |
10 | Важно понимать, что сложный объект это не обязательно объект оперирующий несколькими другими объектами в смысле ООП. Например, нам нужно получить документ состоящий из заголовка, введения, содержания и заключения. Наш документ, это сложный объект. Что бы был какой-то единый порядок составления документа, мы будем использовать паттерн Builder.
11 |
12 | Требуется для реализации:
13 |
14 | 1. Класс Director, который будет распоряжаться строителем и отдавать ему команды в нужном порядке, а строитель будет их выполнять;
15 | 2. Базовый абстрактный класс Builder, который описывает интерфейс строителя, те команды, которые он обязан выполнять;
16 | 3. Класс ConcreteBuilder, который реализует интерфейс строителя и взаимодействует со сложным объектом;
17 | 4. Класс сложного объекта Product.
18 |
19 | [!] В описании паттерна применяются общие понятия, такие как Класс, Объект, Абстрактный класс. Применимо к языку Go, это Пользовательский Тип, Значение этого Типа и Интерфейс. Также в языке Go заместо общепринятого наследования используется агрегирование и встраивание.
20 |
21 | ## -~- THE END -~-
--------------------------------------------------------------------------------
/Creational/Builder/builder.go:
--------------------------------------------------------------------------------
1 | // Package builder is an example of the Builder Pattern.
2 | package builder
3 |
4 | // Builder provides a builder interface.
5 | type Builder interface {
6 | MakeHeader(str string)
7 | MakeBody(str string)
8 | MakeFooter(str string)
9 | }
10 |
11 | // Director implements a manager
12 | type Director struct {
13 | builder Builder
14 | }
15 |
16 | // Construct tells the builder what to do and in what order.
17 | func (d *Director) Construct() {
18 | d.builder.MakeHeader("Header")
19 | d.builder.MakeBody("Body")
20 | d.builder.MakeFooter("Footer")
21 | }
22 |
23 | // ConcreteBuilder implements Builder interface.
24 | type ConcreteBuilder struct {
25 | product *Product
26 | }
27 |
28 | // MakeHeader builds a header of document..
29 | func (b *ConcreteBuilder) MakeHeader(str string) {
30 | b.product.Content += ""
31 | }
32 |
33 | // MakeBody builds a body of document.
34 | func (b *ConcreteBuilder) MakeBody(str string) {
35 | b.product.Content += "" + str + ""
36 | }
37 |
38 | // MakeFooter builds a footer of document.
39 | func (b *ConcreteBuilder) MakeFooter(str string) {
40 | b.product.Content += ""
41 | }
42 |
43 | // Product implementation.
44 | type Product struct {
45 | Content string
46 | }
47 |
48 | // Show returns product.
49 | func (p *Product) Show() string {
50 | return p.Content
51 | }
52 |
--------------------------------------------------------------------------------
/Creational/Builder/builder_test.go:
--------------------------------------------------------------------------------
1 | package builder
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestBuilder(t *testing.T) {
8 |
9 | expect := "" +
10 | "Body" +
11 | ""
12 |
13 | product := new(Product)
14 |
15 | director := Director{&ConcreteBuilder{product}}
16 | director.Construct()
17 |
18 | result := product.Show()
19 |
20 | if result != expect {
21 | t.Errorf("Expect result to %s, but %s", result, expect)
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Creational/FactoryMethod/README.md:
--------------------------------------------------------------------------------
1 |
2 | ## Фабричный метод (FactoryMethod)
3 |
4 | Паттерн Factory Method относится к порождающим паттернам уровня класса и сфокусирован только на отношениях между классами.
5 |
6 | Паттерн Factory Method полезен, когда система должна оставаться легко расширяемой путем добавления объектов новых типов. Этот паттерн является основой для всех порождающих паттернов и может легко трансформироваться под нужды системы. По этому, если перед разработчиком стоят не четкие требования для продукта или не ясен способ организации взаимодействия между продуктами, то для начала можно воспользоваться паттерном Factory Method, пока полностью не сформируются все требования.
7 |
8 | Паттерн Factory Method применяется для создания объектов с определенным интерфейсом, реализации которого предоставляются потомками. Другими словами, есть базовый абстрактный класс фабрики, который говорит, что каждая его наследующая фабрика должна реализовать такой-то метод для создания своих продуктов.
9 |
10 | Реализация фабричного метода может быть разной, в большинстве случаем это зависит от языка реализации. Это может быть полиморфизм или параметризированный метод.
11 |
12 | Пример: К нам приходят файлы трех расширений .txt, .png, .doc. В зависимости от расширения файла мы должны сохранять его в одном из каталогов /file/txt/, /file/png/ и /file/doc/. Значит, у нас будет файловая фабрика с параметризированным фабричным методом, принимающим путь к файлу, который нам нужно сохранить в одном из каталогов. Этот фабричный метод возвращает нам объект, используя который мы можем манипулировать с нашим файлом (сохранить, посмотреть тип и каталог для сохранения). Заметьте, мы никак не указываем какой экземпляр объекта-продукта нам нужно получить, это делает фабричный метод путем определения расширения файла и на его основе выбора подходящего класса продукта. Тем самым, если наша система будет расширяться и доступных расширений файлов станет, например 25, то нам всего лишь нужно будет изменить фабричный метод и реализовать классы продуктов.
13 |
14 | Требуется для реализации:
15 |
16 | 1. Базовый абстрактный класс Creator, описывающий интерфейс, который должна реализовать конкретная фабрика для производства продуктов. Этот базовый класс описывает фабричный метод.
17 | 2. Базовый класс Product, описывающий интерфейс продукта, который возвращает фабрика. Все продукты возвращаемые фабрикой должны придерживаться единого интерфейса.
18 | 3. Класс конкретной фабрики по производству продуктов ConcreteCreator. Этот класс должен реализовать фабричный метод;
19 | 4. Класс реального продукта ConcreteProductA;
20 | 5. Класс реального продукта ConcreteProductB;
21 | 6. Класс реального продукта ConcreteProductC.
22 |
23 | Factory Method отличается от Abstract Factory, тем, что Abstract Factory производит семейство объектов, эти объекты разные, обладают разными интерфейсами, но взаимодействуют между собой. В то время как Factory Method производит продукты придерживающиеся одного интерфейса и эти продукты не связаны между собой, не вступают во взаимодействие.
24 |
25 | [!] В описании паттерна применяются общие понятия, такие как Класс, Объект, Абстрактный класс. Применимо к языку Go, это Пользовательский Тип, Значение этого Типа и Интерфейс. Также в языке Go за место общепринятого наследования используется агрегирование и встраивание.
26 |
27 | ## -~- THE END -~-
28 |
--------------------------------------------------------------------------------
/Creational/FactoryMethod/factory_method.go:
--------------------------------------------------------------------------------
1 | // Package factory_method is an example of the Factory Method pattern.
2 | package factory_method
3 |
4 | import (
5 | "log"
6 | )
7 |
8 | // action helps clients to find out available actions.
9 | type action string
10 |
11 | const (
12 | A action = "A"
13 | B action = "B"
14 | C action = "C"
15 | )
16 |
17 | // Creator provides a factory interface.
18 | type Creator interface {
19 | CreateProduct(action action) Product // Factory Method
20 | }
21 |
22 | // Product provides a product interface.
23 | // All products returned by factory must provide a single interface.
24 | type Product interface {
25 | Use() string // Every product should be usable
26 | }
27 |
28 | // ConcreteCreator implements Creator interface.
29 | type ConcreteCreator struct{}
30 |
31 | // NewCreator is the ConcreteCreator constructor.
32 | func NewCreator() Creator {
33 | return &ConcreteCreator{}
34 | }
35 |
36 | // CreateProduct is a Factory Method.
37 | func (p *ConcreteCreator) CreateProduct(action action) Product {
38 | var product Product
39 |
40 | switch action {
41 | case A:
42 | product = &ConcreteProductA{string(action)}
43 | case B:
44 | product = &ConcreteProductB{string(action)}
45 | case C:
46 | product = &ConcreteProductC{string(action)}
47 | default:
48 | log.Fatalln("Unknown Action")
49 | }
50 |
51 | return product
52 | }
53 |
54 | // ConcreteProductA implements product "A".
55 | type ConcreteProductA struct {
56 | action string
57 | }
58 |
59 | // Use returns product action.
60 | func (p *ConcreteProductA) Use() string {
61 | return p.action
62 | }
63 |
64 | // ConcreteProductB implements product "B".
65 | type ConcreteProductB struct {
66 | action string
67 | }
68 |
69 | // Use returns product action.
70 | func (p *ConcreteProductB) Use() string {
71 | return p.action
72 | }
73 |
74 | // ConcreteProductC implements product "C".
75 | type ConcreteProductC struct {
76 | action string
77 | }
78 |
79 | // Use returns product action.
80 | func (p *ConcreteProductC) Use() string {
81 | return p.action
82 | }
83 |
--------------------------------------------------------------------------------
/Creational/FactoryMethod/factory_method_test.go:
--------------------------------------------------------------------------------
1 | package factory_method
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestFactoryMethod(t *testing.T) {
8 |
9 | assert := []string{"A", "B", "C"}
10 |
11 | factory := NewCreator()
12 | products := []Product{
13 | factory.CreateProduct(A),
14 | factory.CreateProduct(B),
15 | factory.CreateProduct(C),
16 | }
17 |
18 | for i, product := range products {
19 | if action := product.Use(); action != assert[i] {
20 | t.Errorf("Expect action to %s, but %s.\n", assert[i], action)
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Creational/Prototype/README.md:
--------------------------------------------------------------------------------
1 |
2 | ## Прототип (Prototype)
3 |
4 | Паттерн Prototype относится к порождающим паттернам уровня объекта.
5 |
6 | Паттерн Prototype позволяет создавать новые объекты, путем копирования (клонирования) созданного ранее объекта-оригинала-продукта (прототипа).
7 |
8 | Паттерн описывает процесс создания объектов-клонов на основе имеющегося объекта-прототипа, другими словами, паттерн Prototype описывает способ организации процесса клонирования.
9 |
10 | Требуется для реализации:
11 |
12 | 1. Базовый класс Prototype, объявляющий интерфейс клонирования. Все классы его наследующие должны реализовывать этот механизм клонирования;
13 | 2. Класс продукта ConcretePrototypeA, который должен реализовывать этот прототип;
14 | 3. Класс продукта ConcretePrototypeB, который должен реализовывать этот прототип.
15 |
16 | Обычно операция клонирования происходит через метод clone(), который описан в базовом классе и его должен реализовать каждый продукт.
17 |
18 | [!] В описании паттерна применяются общие понятия, такие как Класс, Объект, Абстрактный класс. Применимо к языку Go, это Пользовательский Тип, Значение этого Типа и Интерфейс. Также в языке Go за место общепринятого наследования используется агрегирование и встраивание.
19 |
20 | ## -~- THE END -~-
21 |
--------------------------------------------------------------------------------
/Creational/Prototype/prototype.go:
--------------------------------------------------------------------------------
1 | // Package prototype is an example of the Singleton Pattern.
2 | package prototype
3 |
4 | // Prototyper provides a cloning interface.
5 | type Prototyper interface {
6 | Clone() Prototyper
7 | GetName() string
8 | }
9 |
10 | // ConcreteProduct implements product "A"
11 | type ConcreteProduct struct {
12 | name string // Имя продукта
13 | }
14 |
15 | // NewConcreteProduct is the Prototyper constructor.
16 | func NewConcreteProduct(name string) Prototyper {
17 | return &ConcreteProduct{
18 | name: name,
19 | }
20 | }
21 |
22 | // GetName returns product name
23 | func (p *ConcreteProduct) GetName() string {
24 | return p.name
25 | }
26 |
27 | // Clone returns a cloned object.
28 | func (p *ConcreteProduct) Clone() Prototyper {
29 | return &ConcreteProduct{p.name}
30 | }
31 |
--------------------------------------------------------------------------------
/Creational/Prototype/prototype_test.go:
--------------------------------------------------------------------------------
1 | package prototype
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestPrototype(t *testing.T) {
8 |
9 | product := NewConcreteProduct("A")
10 | cloneProduct := product.Clone()
11 |
12 | if cloneProduct.GetName() != product.GetName() {
13 | t.Error("Expect name \"A\" to equal, but not equal.")
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Creational/README.md:
--------------------------------------------------------------------------------
1 |
2 | ## Порождающие паттерны (Creational)
3 |
4 | Порождающие паттерны делятся на два типа:
5 |
6 | 1. Паттерны уровня класса
7 | 2. Паттерны уровня объекта.
8 |
9 | Паттерны уровня класса изменяют класс создаваемого объекта с помощью наследования.
10 |
11 | Паттерны уровня объекта создают новые объекты с помощью других объектов.
12 |
13 | К паттернам уровня класса относится только «Фабричный метод».
14 |
15 | Порождающие паттерны отвечают за создание классов и объектов. Другими словами порождают классы и порождают объекты.
16 |
17 | * [Абстрактная фабрика (Abstract Factory)](AbstractFactory)
18 | * [Строитель (Builder)](Builder)
19 | * [Фабричный метод (Factory Method)](FactoryMethod)
20 | * [Прототип (Prototype)](Prototype)
21 | * [Одиночка (Singleton)](Singleton)
22 |
23 | ## -~- THE END -~-
--------------------------------------------------------------------------------
/Creational/Singleton/README.md:
--------------------------------------------------------------------------------
1 |
2 | ## Одиночка (Singleton)
3 |
4 | Паттерн Singleton относится к порождающим паттернам уровня объекта.
5 | Паттерн контролирует создание единственного экземпляра некоторого класса и предоставляет доступ к нему.
6 | Другими словами, Singleton гарантирует, что у класса будет только один экземпляр и предоставляет к нему точку доступа, через фабричный метод.
7 |
8 | Требуется для реализации:
9 |
10 | 1. Функция GetInstance, создающая экземпляр класса Singleton только один раз. Если до этого экземпляр уже был создан, то просто возвращает этот экземпляр.
11 |
12 | [!] В описании паттерна применяются общие понятия, такие как Класс, Объект, Абстрактный класс. Применимо к языку Go, это Пользовательский Тип, Значение этого Типа и Интерфейс. Также в языке Go за место общепринятого наследования используется агрегирование и встраивание.
13 |
14 | ## -~- THE END -~-
--------------------------------------------------------------------------------
/Creational/Singleton/singleton.go:
--------------------------------------------------------------------------------
1 | // Package singleton is an example of the Singleton Pattern.
2 | package singleton
3 |
4 | import (
5 | "sync"
6 | )
7 |
8 | // Singleton implementation.
9 | type Singleton struct {
10 | }
11 |
12 | var (
13 | instance *Singleton
14 | once sync.Once
15 | )
16 |
17 | // GetInstance returns singleton
18 | func GetInstance() *Singleton {
19 | once.Do(func() {
20 | instance = &Singleton{}
21 | })
22 | return instance
23 | }
24 |
--------------------------------------------------------------------------------
/Creational/Singleton/singleton_test.go:
--------------------------------------------------------------------------------
1 | package singleton
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestSingleton(t *testing.T) {
8 |
9 | instance1 := GetInstance()
10 | instance2 := GetInstance()
11 |
12 | if instance1 != instance2 {
13 | t.Error("Objects are not equal!\n")
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2015 Alexander Gromov
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in
14 | all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | ## Паттерны проектирования с примерами на Golang
3 |
4 | Это коллекция из 22 популярных паттернов проектирования с примерами кода на языке Go и кратким описанием паттерна.
5 |
6 | В кратких описаниях будут употребляться классические термины, такие как Класс, Объект, Абстрактный Класс. Применимо к языку Go, это Тип, Значение этого типа и Интерфейс (где это возможно).
7 |
8 | Умение правильно использовать шаблоны проектирования, так сказать, в нужном месте и в нужное время, помогут сохранить ваши нервные клетки.
9 |
10 | ## Установка
11 |
12 | Вы можете скачать этот репозиторий и запустить тесты
13 |
14 | ```bash
15 | $ go get github.com/alexandergrom/go-patterns
16 | ```
17 |
18 | ## Паттерны
19 |
20 | ### [Порождающие (Creational)](Creational)
21 |
22 | * [Абстрактная фабрика (Abstract Factory)](Creational/AbstractFactory)
23 | * [Строитель (Builder)](Creational/Builder)
24 | * [Фабричный метод (Factory Method)](Creational/FactoryMethod)
25 | * [Прототип (Prototype)](Creational/Prototype)
26 | * [Одиночка (Singleton)](Creational/Singleton)
27 |
28 | ### [Структурные (Structural)](Structural)
29 |
30 | * [Адаптер (Adapter)](Structural/Adapter)
31 | * [Мост (Bridge)](Structural/Bridge)
32 | * [Компоновщик (Composite)](Structural/Composite)
33 | * [Декоратор (Decorator)](Structural/Decorator)
34 | * [Фасад (Facade)](Structural/Facade)
35 | * [Приспособленец (Flyweight)](Structural/Flyweight)
36 | * [Заместитель (Proxy)](Structural/Proxy)
37 |
38 | ### [Поведенческие (Behavioral)](Behavioral)
39 |
40 | * [Цепочка ответственности (Chain Of Responsibility)](Behavioral/ChainOfResponsibility)
41 | * [Команда (Command)](Behavioral/Command)
42 | * [Итератор (Iterator)](Behavioral/Iterator)
43 | * [Посредник (Mediator)](Behavioral/Mediator)
44 | * [Хранитель (Memento)](Behavioral/Memento)
45 | * [Наблюдатель (Observer)](Behavioral/Observer)
46 | * [Состояние (State)](Behavioral/State)
47 | * [Стратегия (Strategy)](Behavioral/Strategy)
48 | * [Шаблонный метод (Template Method)](Behavioral/TemplateMethod)
49 | * [Посетитель (Visitor)](Behavioral/Visitor)
50 |
51 | ## -~- THE END -~-
52 |
--------------------------------------------------------------------------------
/Structural/Adapter/README.md:
--------------------------------------------------------------------------------
1 |
2 | ## Адаптер (Adapter)
3 |
4 | Паттерн Adapter относится к структурным паттернам уровня класса.
5 |
6 | Часто в новом проекте разработчики хотят повторно использовать уже существующий код. Например, имеющиеся классы могут обладать нужной функциональностью и иметь при этом несовместимые интерфейсы. В таких случаях следует использовать паттерн Adapter.
7 |
8 | Смысл работы этого паттерна в том, что если у вас есть класс и его интерфейс не совместим с кодом вашей системы, то что бы разрешить этот конфликт, мы не изменяем код этого класса, а пишем для него адаптер. Другими словами Adapter адаптирует существующий код к требуемому интерфейсу (является переходником).
9 |
10 | Требуется для реализации:
11 |
12 | 1. Интерфейс Target, описывающий целевой интерфейс (тот интерфейс с которым наша система хотела бы работать);
13 | 2. Класс Adaptee, который наша система должна адаптировать под себя;
14 | 3. Класс Adapter, адаптер реализующий целевой интерфейс.
15 |
16 | [!] В описании паттерна применяются общие понятия, такие как Класс, Объект, Абстрактный класс. Применимо к языку Go, это Пользовательский Тип, Значение этого Типа и Интерфейс. Также в языке Go за место общепринятого наследования используется агрегирование и встраивание.
17 |
18 | ## -~- THE END -~-
--------------------------------------------------------------------------------
/Structural/Adapter/adapter.go:
--------------------------------------------------------------------------------
1 | // Package adapter is an example of the Adapter Pattern.
2 | package adapter
3 |
4 | // Target provides an interface with which the system should work.
5 | type Target interface {
6 | Request() string
7 | }
8 |
9 | // Adaptee implements system to be adapted.
10 | type Adaptee struct {
11 | }
12 |
13 | // NewAdapter is the Adapter constructor.
14 | func NewAdapter(adaptee *Adaptee) Target {
15 | return &Adapter{adaptee}
16 | }
17 |
18 | // SpecificRequest implementation.
19 | func (a *Adaptee) SpecificRequest() string {
20 | return "Request"
21 | }
22 |
23 | // Adapter implements Target interface and is an adapter.
24 | type Adapter struct {
25 | *Adaptee
26 | }
27 |
28 | // Request is an adaptive method.
29 | func (a *Adapter) Request() string {
30 | return a.SpecificRequest()
31 | }
32 |
--------------------------------------------------------------------------------
/Structural/Adapter/adapter_test.go:
--------------------------------------------------------------------------------
1 | package adapter
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestAdapter(t *testing.T) {
8 |
9 | adapter := NewAdapter(&Adaptee{})
10 |
11 | req := adapter.Request()
12 |
13 | if req != "Request" {
14 | t.Errorf("Expect volume to %s, but %s", "Request", req)
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Structural/Bridge/README.md:
--------------------------------------------------------------------------------
1 |
2 | ## Мост (Bridge)
3 |
4 | Паттерн Bridge относится к структурным паттернам уровня объекта.
5 |
6 | Паттерн Bridge позволяет разделить объект на абстракцию и реализацию так, чтобы они могли изменяться независимо друг от друга.
7 |
8 | Если для одной абстракции возможно несколько реализаций, то обычно используют наследование. Однако такой подход не всегда удобен, так как наследование жестко привязывает реализацию к абстракции, что затрудняет независимую модификацию и усложняет их повторное использование.
9 |
10 | Паттерн следует применять, когда у нас имеется абстракция и несколько её реализаций. Разумеется, нет смысла отделять абстракцию от реализации, если реализация может быть только одна.
11 |
12 | Я не нашел не одного адекватного описания паттерна "Мост". Все что мне встречалось, либо не соответствует действительности и примеры высосаны из пальца или очень размыты. Из того, что я понял и могу объяснить на пальцах - Мост это хитрая агрегация. Класс реализующий изделие, реализует интерфейс агрегируемого класса, который подсовывается на этапе создания экземпляра класса изделия.
13 |
14 | Как я понял... у нас есть 3 машины и 3 разных двигателя. Каждый двигатель подходит к каждой машине, т.е. она реализует его интерфейс. Если делать это наследованием, мы получим 9 разных классом. Получается у каждой машины 3 модификации. Это неудобно, поэтому мы будем подсовывать двигатель на этапе создания машины. Так же каждый двигатель, может работать на разном топливе, дизель или бензин, что бы не плодить 6 разных реализаций, при создании двигателя мы будем подсовывать в него тип топлива.
15 |
16 | Для реализации паттерна в этом примере необходимо в базовом классе автомобилей добавить поле для хранения указателя на тип реализации, значение которого класс будет получать в своём конструкторе, и вызывать по необходимости методы вложенного объекта.
17 |
18 | Требуется для реализации:
19 |
20 | 1. Базовый абстрактный класс (в нашем случаем описывающий автомобиль);
21 | 2. Класс реализующий базовый класс. В нем есть свойство в которое мы будем подсовывать указатель на используемый двигатель (машина может работать с любым из представленных двигателей);
22 | 3. Абстракция двигателя;
23 | 4. Реализация двигателя.
24 |
25 | В общем свойство хранящее указатель на используемый объект и есть мост. Мы в него можем подсовывать разные объекты, главное, что бы они имели одинаковый интерфейс.
26 |
27 | [!] В описании паттерна применяются общие понятия, такие как Класс, Объект, Абстрактный класс. Применимо к языку Go, это Пользовательский Тип, Значение этого Типа и Интерфейс. Также в языке Go заместо общепринятого наследования используется агрегирование и встраивание.
28 |
29 | ## -~- THE END -~-
--------------------------------------------------------------------------------
/Structural/Bridge/bridge.go:
--------------------------------------------------------------------------------
1 | // Package bridge is an example of the Bridge Pattern.
2 | package bridge
3 |
4 | // Carer provides car interface.
5 | type Carer interface {
6 | Rase() string
7 | }
8 |
9 | // Enginer provides engine interface.
10 | type Enginer interface {
11 | GetSound() string
12 | }
13 |
14 | // Car implementation.
15 | type Car struct {
16 | engine Enginer
17 | }
18 |
19 | // NewCar is the Car constructor.
20 | func NewCar(engine Enginer) Carer {
21 | return &Car{
22 | engine: engine,
23 | }
24 | }
25 |
26 | // Rase implementation.
27 | func (c *Car) Rase() string {
28 | return c.engine.GetSound()
29 | }
30 |
31 | // EngineSuzuki implements Suzuki engine.
32 | type EngineSuzuki struct {
33 | }
34 |
35 | // GetSound returns sound of the engine.
36 | func (e *EngineSuzuki) GetSound() string {
37 | return "SssuuuuZzzuuuuKkiiiii"
38 | }
39 |
40 | // EngineHonda implements Honda engine.
41 | type EngineHonda struct {
42 | }
43 |
44 | // GetSound returns sound of the engine.
45 | func (e *EngineHonda) GetSound() string {
46 | return "HhoooNnnnnnnnnDddaaaaaaa"
47 | }
48 |
49 | // EngineLada implements Lada engine.
50 | type EngineLada struct {
51 | }
52 |
53 | // GetSound returns sound of the engine.
54 | func (e *EngineLada) GetSound() string {
55 | return "PhhhhPhhhhPhPhPhPhPh"
56 | }
57 |
--------------------------------------------------------------------------------
/Structural/Bridge/bridge_test.go:
--------------------------------------------------------------------------------
1 | package bridge
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestBridge(t *testing.T) {
8 |
9 | expect := "SssuuuuZzzuuuuKkiiiii"
10 |
11 | car := NewCar(&EngineSuzuki{})
12 |
13 | sound := car.Rase()
14 |
15 | if sound != expect {
16 | t.Errorf("Expect sound to %s, but %s", expect, sound)
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Structural/Composite/README.md:
--------------------------------------------------------------------------------
1 |
2 | ## Компоновщик (Composite)
3 |
4 | Паттерн Composite относится к структурным паттернам уровня объекта.
5 |
6 | Паттерн Composite группирует схожие объекты в древовидные структуры.
7 |
8 | Для построения дерева будут использоваться массивы, представляющие ветви дерева.
9 |
10 | Требуется для реализации:
11 |
12 | 1. Базовый абстрактный класс Component который предоставляет интерфейс, как для ветвей, так и для листьев дерева;
13 | 2. Класс Composite, реализующий интерфейс Component и являющийся ветвью дерева;
14 | 3. Класс Leaf, реализующий интерфейс Component и являющийся листом дерева.
15 |
16 | Обратите внимание, что лист дерева является классом листовых узлов и не может иметь потомков (из листа не может вырасти ветвь или другой лист).
17 |
18 | Ветви дерева задают поведение объектов, входящих в структуру дерева, у которых есть потомки, а также сами хранит в себе компоненты дерева. Другим словами ветви могут содержать другие ветви и листья.
19 |
20 | Основным назначением паттерна, является обеспечение единого интерфейса как к составному (ветви) так и конечному (листу) объекту, что бы клиент не задумывался над тем, с каким объектом он работает.
21 |
22 | [!] В описании паттерна применяются общие понятия, такие как Класс, Объект, Абстрактный класс. Применимо к языку Go, это Пользовательский Тип, Значение этого Типа и Интерфейс. Также в языке Go за место общепринятого наследования используется агрегирование и встраивание.
23 |
24 | ## -~- THE END -~-
--------------------------------------------------------------------------------
/Structural/Composite/composite.go:
--------------------------------------------------------------------------------
1 | // Package composite is an example of the Composite Pattern.
2 | package composite
3 |
4 | // Component provides an interface for branches and leaves of a tree.
5 | type Component interface {
6 | Add(child Component)
7 | Name() string
8 | Child() []Component
9 | Print(prefix string) string
10 | }
11 |
12 | // Directory implements branches of a tree
13 | type Directory struct {
14 | name string
15 | childs []Component
16 | }
17 |
18 | // Add appends an element to the tree branch.
19 | func (d *Directory) Add(child Component) {
20 | d.childs = append(d.childs, child)
21 | }
22 |
23 | // Name returns name of the Component.
24 | func (d *Directory) Name() string {
25 | return d.name
26 | }
27 |
28 | // Child returns child elements.
29 | func (d *Directory) Child() []Component {
30 | return d.childs
31 | }
32 |
33 | // Print returns the branche in string representation.
34 | func (d *Directory) Print(prefix string) string {
35 | result := prefix + "/" + d.Name() + "\n"
36 | for _, val := range d.Child() {
37 | result += val.Print(prefix + "/" + d.Name())
38 | }
39 | return result
40 | }
41 |
42 | // File implements a leaves of a tree
43 | type File struct {
44 | name string
45 | }
46 |
47 | // Add implementation.
48 | func (f *File) Add(child Component) {
49 | }
50 |
51 | // Name returns name of the Component.
52 | func (f *File) Name() string {
53 | return f.name
54 | }
55 |
56 | // Child implementation.
57 | func (f *File) Child() []Component {
58 | return []Component{}
59 | }
60 |
61 | // Print returns the leave in string representation.
62 | func (f *File) Print(prefix string) string {
63 | return prefix + "/" + f.Name() + "\n"
64 | }
65 |
66 | // NewDirectory is constructor.
67 | func NewDirectory(name string) *Directory {
68 | return &Directory{
69 | name: name,
70 | }
71 | }
72 |
73 | // NewFile is constructor.
74 | func NewFile(name string) *File {
75 | return &File{
76 | name: name,
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/Structural/Composite/composite_test.go:
--------------------------------------------------------------------------------
1 | package composite
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestComposite(t *testing.T) {
8 |
9 | expect := "/root\n/root/usr\n/root/usr/B\n/root/A\n"
10 |
11 | rootDir := NewDirectory("root")
12 |
13 | usrDir := NewDirectory("usr")
14 | fileA := NewFile("A")
15 |
16 | rootDir.Add(usrDir)
17 | rootDir.Add(fileA)
18 |
19 | fileB := NewFile("B")
20 |
21 | usrDir.Add(fileB)
22 |
23 | result := rootDir.Print("")
24 |
25 | if result != expect {
26 | t.Errorf("Expect result to equal %s, but %s.\n", expect, result)
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Structural/Decorator/README.md:
--------------------------------------------------------------------------------
1 |
2 | ## Декоратор (Decorator)
3 |
4 | Паттерн Decorator относится к структурным паттернам уровня объекта.
5 |
6 | Паттерн Decorator используется для расширения функциональности объектов путем динамического добавления объекту новых возможностей. При реализации паттерна используется отношение композиции.
7 |
8 | Сущность работы декоратора заключается в обёртывании готового объекта новым функционалом, при этом весь оригинальный интерфейс объекта остается доступным, путем передачи декоратором всех запросов обернутому объекту.
9 |
10 | Требуется для реализации:
11 |
12 | 1. Базовый абстрактный класс Component который предоставляет интерфейс для класса декоратора и компонента;
13 | 2. Класс ConcreteDecorator, реализующий интерфейс Component и перезагружающий все методы компонента, по необходимости к ним добавляется функционал;
14 | 3. Класс ConcreteComponent реализующий интерфейс Component и который будет обернут декоратором.
15 |
16 | При такой структуре нам не важно является ли компонент декоратором или конкретной реализацией, так как интерфейс у них совпадает, и мы можем делать цепочки декораторов. Тем самым динамически менять состояние и поведение объекта.
17 |
18 | Я слышал пример с Калсоном и мне он очень понравился. У нас есть Карлсон, мы на него одеваем комбинезон тем самым меняя его состояние, потом на штаны одеваем пропеллер тем самым меняем поведение. Пропеллер в зависимости от ситуации можно снять, изменив поведение на обратное или можно одеть другой комбинезон с другими свойствами.
19 |
20 | [!] В описании паттерна применяются общие понятия, такие как Класс, Объект, Абстрактный класс. Применимо к языку Go, это Пользовательский Тип, Значение этого Типа и Интерфейс. Также в языке Go за место общепринятого наследования используется агрегирование и встраивание.
21 |
22 | ## -~- THE END -~-
--------------------------------------------------------------------------------
/Structural/Decorator/decorator.go:
--------------------------------------------------------------------------------
1 | // Package decorator is an example of the Decorator Pattern.
2 | package decorator
3 |
4 | // Component provides an interface for a decorator and component.
5 | type Component interface {
6 | Operation() string
7 | }
8 |
9 | // ConcreteComponent implements a component.
10 | type ConcreteComponent struct {
11 | }
12 |
13 | // Operation implementation.
14 | func (c *ConcreteComponent) Operation() string {
15 | return "I am component!"
16 | }
17 |
18 | // ConcreteDecorator implements a decorator.
19 | type ConcreteDecorator struct {
20 | component Component
21 | }
22 |
23 | // Operation wraps operation of component
24 | func (d *ConcreteDecorator) Operation() string {
25 | return "" + d.component.Operation() + ""
26 | }
27 |
--------------------------------------------------------------------------------
/Structural/Decorator/decorator_test.go:
--------------------------------------------------------------------------------
1 | package decorator
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestDecorator(t *testing.T) {
8 |
9 | expect := "I am component!"
10 |
11 | decorator := &ConcreteDecorator{&ConcreteComponent{}}
12 |
13 | result := decorator.Operation()
14 |
15 | if result != expect {
16 | t.Errorf("Expect result to equal %s, but %s.\n", expect, result)
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Structural/Facade/README.md:
--------------------------------------------------------------------------------
1 |
2 | ## Фасад (Facade)
3 |
4 | Паттерн Facade относится к структурным паттернам уровня объекта.
5 |
6 | Паттерн Facade предоставляет высокоуровневый унифицированный интерфейс в виде набора имен методов к набору взаимосвязанных классов или объектов некоторой подсистемы, что облегчает ее использование.
7 |
8 | Разбиение сложной системы на подсистемы позволяет упростить процесс разработки, а также помогает максимально снизить зависимости одной подсистемы от другой. Однако использовать такие подсистемы становиться довольно сложно. Один из способов решения этой проблемы является паттерн Facade. Наша задача, сделать простой, единый интерфейс, через который можно было бы взаимодействовать с подсистемами.
9 |
10 | В качестве примера можно привести интерфейс автомобиля. Современные автомобили имеют унифицированный интерфейс для водителя, под которым скрывается сложная подсистема. Благодаря применению навороченной электроники, делающей большую часть работы за водителя, тот может с лёгкостью управлять автомобилем, не задумываясь, как там все работает.
11 |
12 | Требуется для реализации:
13 |
14 | 1. Класс Facade предоставляющий унифицированный доступ для классов подсистемы;
15 | 2. Класс подсистемы SubSystemA;
16 | 3. Класс подсистемы SubSystemB;
17 | 4. Класс подсистемы SubSystemC.
18 |
19 | Заметьте, что фасад не является единственной точкой доступа к подсистеме, он не ограничивает возможности, которые могут понадобиться "продвинутым" пользователям, желающим работать с подсистемой напрямую.
20 |
21 | [!] В описании паттерна применяются общие понятия, такие как Класс, Объект, Абстрактный класс. Применимо к языку Go, это Пользовательский Тип, Значение этого Типа и Интерфейс. Также в языке Go за место общепринятого наследования используется агрегирование и встраивание.
22 |
23 | ## -~- THE END -~-
--------------------------------------------------------------------------------
/Structural/Facade/facade.go:
--------------------------------------------------------------------------------
1 | // Package facade is an example of the Facade Pattern.
2 | package facade
3 |
4 | import (
5 | "strings"
6 | )
7 |
8 | // NewMan creates man.
9 | func NewMan() *Man {
10 | return &Man{
11 | house: &House{},
12 | tree: &Tree{},
13 | child: &Child{},
14 | }
15 | }
16 |
17 | // Man implements man and facade.
18 | type Man struct {
19 | house *House
20 | tree *Tree
21 | child *Child
22 | }
23 |
24 | // Todo returns that man must do.
25 | func (m *Man) Todo() string {
26 | result := []string{
27 | m.house.Build(),
28 | m.tree.Grow(),
29 | m.child.Born(),
30 | }
31 | return strings.Join(result, "\n")
32 | }
33 |
34 | // House implements a subsystem "House"
35 | type House struct {
36 | }
37 |
38 | // Build implementation.
39 | func (h *House) Build() string {
40 | return "Build house"
41 | }
42 |
43 | // Tree implements a subsystem "Tree"
44 | type Tree struct {
45 | }
46 |
47 | // Grow implementation.
48 | func (t *Tree) Grow() string {
49 | return "Tree grow"
50 | }
51 |
52 | // Child implements a subsystem "Child"
53 | type Child struct {
54 | }
55 |
56 | // Born implementation.
57 | func (c *Child) Born() string {
58 | return "Child born"
59 | }
60 |
--------------------------------------------------------------------------------
/Structural/Facade/facade_test.go:
--------------------------------------------------------------------------------
1 | package facade
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestFacade(t *testing.T) {
8 |
9 | expect := "Build house\nTree grow\nChild born"
10 |
11 | man := NewMan()
12 |
13 | result := man.Todo()
14 |
15 | if result != expect {
16 | t.Errorf("Expect result to equal %s, but %s.\n", expect, result)
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Structural/Flyweight/README.md:
--------------------------------------------------------------------------------
1 |
2 | ## Приспособленец (Flyweight)
3 |
4 | Паттерн Flyweight относится к структурным паттернам уровня объекта.
5 |
6 | Паттерн Flyweight используется для эффективной поддержки большого числа мелких объектов, он позволяет повторно использовать мелкие объекты в различном контексте.
7 |
8 | Требуется для реализации:
9 |
10 | 1. Класс FlyweightFactory, являющейся модифицированным паттерном фабрики, для создания приспособленцев;
11 | 2. Базовый абстрактный класс Flyweight, для описания общего интерфейса приспособленцев;
12 | 3. Класс ConcreteFlyweight реализующий приспособленца, который будет замещать собой одинаковые мелкие объекты.
13 |
14 | Суть в том, что мы можем запрашивать приспособленцев у фабрики по запросу, в свою очередь она будет отдавать те объекты, которые уже были созданы, или создавать новые. Это означает, что мы будем использовать уже созданные объекты, а не создавать ещё больше, если объекты под наши нужны уже имеются. Также стоит обратить внимание, что приспособленцы имеют внутреннее и внешние состояние. Фабрика находит приспособленцев по внутреннему состоянию, а внешнее состояние передается в его методы.
15 |
16 | [!] В описании паттерна применяются общие понятия, такие как Класс, Объект, Абстрактный класс. Применимо к языку Go, это Пользовательский Тип, Значение этого Типа и Интерфейс. Также в языке Go за место общепринятого наследования используется агрегирование и встраивание.
17 |
18 | ## -~- THE END -~-
--------------------------------------------------------------------------------
/Structural/Flyweight/flyweight.go:
--------------------------------------------------------------------------------
1 | // Package flyweight is an example of the Flyweight Pattern.
2 | package flyweight
3 |
4 | import "fmt"
5 |
6 | // Flyweighter interface
7 | type Flyweighter interface {
8 | Draw(width, height int, opacity float64) string
9 | }
10 |
11 | // FlyweightFactory implements a factory.
12 | // If a suitable flyweighter is in pool, then returns it.
13 | type FlyweightFactory struct {
14 | pool map[string]Flyweighter
15 | }
16 |
17 | // GetFlyweight creates or returns a suitable Flyweighter by state.
18 | func (f *FlyweightFactory) GetFlyweight(filename string) Flyweighter {
19 | if f.pool == nil {
20 | f.pool = make(map[string]Flyweighter)
21 | }
22 | if _, ok := f.pool[filename]; !ok {
23 | f.pool[filename] = &ConcreteFlyweight{filename: filename}
24 | }
25 | return f.pool[filename]
26 | }
27 |
28 | // ConcreteFlyweight implements a Flyweighter interface.
29 | type ConcreteFlyweight struct {
30 | filename string // internal state
31 | }
32 |
33 | // Draw draws image. Args width, height and opacity is external state.
34 | func (f *ConcreteFlyweight) Draw(width, height int, opacity float64) string {
35 | return fmt.Sprintf("draw image: %s, width: %d, height: %d, opacity: %.2f", f.filename, width, height, opacity)
36 | }
37 |
--------------------------------------------------------------------------------
/Structural/Flyweight/flyweight_test.go:
--------------------------------------------------------------------------------
1 | package flyweight
2 |
3 | import (
4 | "strconv"
5 | "testing"
6 | )
7 |
8 | func TestFlyweight(t *testing.T) {
9 | var testCases = []struct {
10 | filename string
11 | width int
12 | height int
13 | opacity float64
14 | expect string
15 | }{
16 | {"cat.jpg", 100, 100, 0.95, "draw image: cat.jpg, width: 100, height: 100, opacity: 0.95"},
17 | {"cat.jpg", 200, 200, 0.75, "draw image: cat.jpg, width: 200, height: 200, opacity: 0.75"},
18 | {"dog.jpg", 300, 300, 0.50, "draw image: dog.jpg, width: 300, height: 300, opacity: 0.50"},
19 | }
20 |
21 | var factory = new(FlyweightFactory)
22 |
23 | for i, tt := range testCases {
24 | t.Run("case "+strconv.Itoa(i), func(t *testing.T) {
25 | var flyweight = factory.GetFlyweight(tt.filename)
26 | var result = flyweight.Draw(tt.width, tt.height, tt.opacity)
27 | if result != tt.expect {
28 | t.Errorf("Expect result to equal %s, but %s.\n", tt.expect, result)
29 | }
30 | })
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Structural/Proxy/README.md:
--------------------------------------------------------------------------------
1 |
2 | ## Заместитель (Proxy)
3 |
4 | Паттерн Proxy относится к структурным паттернам уровня объекта.
5 |
6 | Паттерн Proxy предоставляет объект для контроля доступа к другому объекту.
7 |
8 | Другое название паттерна - "Суррогат". В этом понимании, это предмет или продукт, заменяющий собой какой-либо другой предмет или продукт, с которым суррогат имеет лишь некоторые общие свойства, но он не обладает всеми качествами оригинального предмета или продукта.
9 |
10 | Паттерна Proxy выдвигается ряд важных требований, а именно то, что оригинальный объект и его суррогат должны взаимодействовать друг с другом, а также должна быть возможность, замещения оригинальным объектом, суррогата в месте его использования, соответственно интерфейсы взаимодействия оригинального объекта и его суррогата должны совпадать.
11 |
12 | Вам будет легче понять паттерн, если вы смотрели фильм "Суррогаты".
13 |
14 | Требуется для реализации:
15 |
16 | 1. Интерфейс Subject, являющейся общим интерфейсом для реального объекта и его суррогата;
17 | 2. Класс RealSubject, реализующий реальный объект;
18 | 3. Класс Proxy, реализующий объект суррогата. Хранит в себе ссылку на реальный объект, что позволяет заместителю обращаться к реальному объект напрямую;
19 |
20 | Например, паттерн Proxy можно использовать, если нам нужно управлять ресурсоемкими объектами, но мы не хотим создавать экземпляры таких объектов до момента их реального использования.
21 |
22 | Вы можете подумать, что это тоже самое, что и Adapter или Decorator. Но...
23 |
24 | Proxy предоставляет своему объекту тот же интерфейс.
25 | Adapter предоставляет другой интерфейс.
26 | Decorator предоставляет расширенный интерфейс.
27 |
28 | [!] В описании паттерна применяются общие понятия, такие как Класс, Объект, Абстрактный класс. Применимо к языку Go, это Пользовательский Тип, Значение этого Типа и Интерфейс. Также в языке Go за место общепринятого наследования используется агрегирование и встраивание.
29 |
30 | ## -~- THE END -~-
--------------------------------------------------------------------------------
/Structural/Proxy/proxy.go:
--------------------------------------------------------------------------------
1 | // Package proxy is an example of the Adapter Pattern.
2 | package proxy
3 |
4 | // Subject provides an interface for a real subject and its surrogate.
5 | type Subject interface {
6 | Send() string
7 | }
8 |
9 | // Proxy implements a surrogate.
10 | type Proxy struct {
11 | realSubject Subject
12 | }
13 |
14 | // Send sends a message
15 | func (p *Proxy) Send() string {
16 | if p.realSubject == nil {
17 | p.realSubject = &RealSubject{}
18 | }
19 | return "" + p.realSubject.Send() + ""
20 | }
21 |
22 | // RealSubject implements a real subject
23 | type RealSubject struct {
24 | }
25 |
26 | // Send sends a message
27 | func (s *RealSubject) Send() string {
28 | return "I’ll be back!"
29 | }
30 |
--------------------------------------------------------------------------------
/Structural/Proxy/proxy_test.go:
--------------------------------------------------------------------------------
1 | package proxy
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestProxy(t *testing.T) {
8 |
9 | expect := "I’ll be back!"
10 |
11 | proxy := new(Proxy)
12 |
13 | result := proxy.Send()
14 |
15 | if result != expect {
16 | t.Errorf("Expect result to equal %s, but %s.\n", expect, result)
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Structural/README.md:
--------------------------------------------------------------------------------
1 |
2 | ### Структурные паттерны (Structural)
3 |
4 | Структурные паттерны делятся на два типа:
5 |
6 | 1. Паттерны уровня класса
7 | 2. Паттерны уровня объекта.
8 |
9 | Паттерны уровня класса описывают взаимодействия между классами и их подклассами. Такие отношения выражаются путем наследования и реализации классов. Тут базовый класс определяет интерфейс, а подклассы - реализацию.
10 |
11 | Паттерны уровня объекта описывают взаимодействия между объектами. Такие отношения выражаются связями - ассоциацией, агрегацией и композицией. Тут структуры строятся путем объединения объектов некоторых классов.
12 |
13 | Ассоциация - отношение, когда объекты двух классов могут ссылаться один на другой. Например, свойство класса содержит экземпляр другого класса.
14 |
15 | Агрегация – частная форма ассоциации. Агрегация применяется, когда один объект должен быть контейнером для других объектов и время существования этих объектов никак не зависит от времени существования объекта контейнера. Вообщем, если контейнер будет уничтожен, то входящие в него объекты не пострадают. Например, мы создали объект, а потом передали его в объект контейнер, каким-либо образом, можно в метод объекта контейнера передать или присвоить сразу свойству контейнера извне. Значит, при удалении контейнера мы ни как не затронем наш созданный объект, который может взаимодействовать и с другими контейнерами.
16 |
17 | Композиция – Тоже самое, что и агрегация, но составные объекты не могут существовать отдельно от объекта контейнера и если контейнер будет уничтожен, то всё его содержимое будет уничтожено тоже. Например, мы создали объект в методе объекта контейнера и присвоили его свойству объекта контейнера. Из вне, о нашем созданном объекте никто не знает, значит, при удалении контейнера, созданный объект будет удален так же, т.к. на него нет ссылки извне.
18 |
19 | К паттернам уровня класса относится только «Адаптер». Смысл его работы в том, что если у вас есть класс и его интерфейс не совместим с библиотеками вашей системы, то что бы разрешить этот конфликт, мы не изменяем код этого класса, а пишем для него адаптер.
20 |
21 | Все структурные паттерны отвечают за создание правильной структуры системы, в которой без труда смогут взаимодействовать между собой уже имеющиеся классы и объекты.
22 |
23 | * [Адаптер (Adapter)](Adapter)
24 | * [Мост (Bridge)](Bridge)
25 | * [Компоновщик (Composite)](Composite)
26 | * [Декоратор (Decorator)](Decorator)
27 | * [Фасад (Facade)](Facade)
28 | * [Приспособленец (Flyweight)](Flyweight)
29 | * [Заместитель (Proxy)](Proxy)
30 |
31 | ## -~- THE END -~-
32 |
--------------------------------------------------------------------------------
/Unsorted/README.md:
--------------------------------------------------------------------------------
1 |
2 | ### Неотсортированные и наброски
3 |
4 | * [Спецификация (Specification)](Specification)
5 |
6 | ## -~- THE END -~-
7 |
--------------------------------------------------------------------------------
/Unsorted/Specification/README.md:
--------------------------------------------------------------------------------
1 |
2 | ## Спецификация (Specification)
3 |
4 | Спецификация — шаблон проектирования, посредством которого представление правил бизнес логики может быть преобразовано в виде цепочки объектов, связанных операциями булевой логики.
5 |
6 | Больше информации в Wikipedia
7 | https://en.wikipedia.org/wiki/Specification_pattern
8 |
9 | ## -~- THE END -~-
10 |
--------------------------------------------------------------------------------
/Unsorted/Specification/specification.go:
--------------------------------------------------------------------------------
1 | // Pattern Specification
2 | //
3 | // In the following example, we are retrieving invoices and sending them to a collection agency if
4 | // 1. they are overdue,
5 | // 2. notices have been sent, and
6 | // 3. they are not already with the collection agency.
7 | // This example is meant to show the end result of how the logic is 'chained' together.
8 | //
9 | // This usage example assumes a previously defined OverdueSpecification class
10 | // that is satisfied when an invoice's due date is 30 days or older,
11 | // a NoticeSentSpecification class that is satisfied when three notices
12 | // have been sent to the customer, and an InCollectionSpecification class
13 | // that is satisfied when an invoice has already been sent to the collection
14 | // agency. The implementation of these classes isn't important here.
15 |
16 | package specification
17 |
18 | // Data for analysis
19 | type Invoice struct {
20 | Day int
21 | Notice int
22 | IsSent bool
23 | }
24 |
25 | /////
26 |
27 | // Invoice Specification Interface
28 | type Specification interface {
29 | IsSatisfiedBy(Invoice) bool
30 | And(Specification) Specification
31 | Or(Specification) Specification
32 | Not() Specification
33 | Relate(Specification)
34 | }
35 |
36 | /////
37 |
38 | // Invoice BaseSpecification
39 | type BaseSpecification struct {
40 | Specification
41 | }
42 |
43 | // Check specification
44 | func (self *BaseSpecification) IsSatisfiedBy(elm Invoice) bool {
45 | return false
46 | }
47 |
48 | // Condition AND
49 | func (self *BaseSpecification) And(spec Specification) Specification {
50 | a := &AndSpecification{
51 | self.Specification, spec,
52 | }
53 | a.Relate(a)
54 | return a
55 | }
56 |
57 | // Condition OR
58 | func (self *BaseSpecification) Or(spec Specification) Specification {
59 | a := &OrSpecification{
60 | self.Specification, spec,
61 | }
62 | a.Relate(a)
63 | return a
64 | }
65 |
66 | // Condition NOT
67 | func (self *BaseSpecification) Not() Specification {
68 | a := &NotSpecification{
69 | self.Specification,
70 | }
71 | a.Relate(a)
72 | return a
73 | }
74 |
75 | // Relate to specification
76 | func (self *BaseSpecification) Relate(spec Specification) {
77 | self.Specification = spec
78 | }
79 |
80 | /////
81 |
82 | // AndSpecification
83 | type AndSpecification struct {
84 | Specification
85 | compare Specification
86 | }
87 |
88 | // Check specification
89 | func (self *AndSpecification) IsSatisfiedBy(elm Invoice) bool {
90 | return self.Specification.IsSatisfiedBy(elm) && self.compare.IsSatisfiedBy(elm)
91 | }
92 |
93 | /////
94 |
95 | // OrSpecification
96 | type OrSpecification struct {
97 | Specification
98 | compare Specification
99 | }
100 |
101 | // Check specification
102 | func (self *OrSpecification) IsSatisfiedBy(elm Invoice) bool {
103 | return self.Specification.IsSatisfiedBy(elm) || self.compare.IsSatisfiedBy(elm)
104 | }
105 |
106 | /////
107 |
108 | // NotSpecification
109 | type NotSpecification struct {
110 | Specification
111 | }
112 |
113 | // Check specification
114 | func (self *NotSpecification) IsSatisfiedBy(elm Invoice) bool {
115 | return !self.Specification.IsSatisfiedBy(elm)
116 | }
117 |
118 | /////
119 |
120 | // Invoice's due date is 30 days or older
121 | type OverDueSpecification struct {
122 | Specification
123 | }
124 |
125 | // Check specification
126 | func (self *OverDueSpecification) IsSatisfiedBy(elm Invoice) bool {
127 | return elm.Day >= 30
128 | }
129 |
130 | // Constructor
131 | func NewOverDueSpecification() Specification {
132 | a := &OverDueSpecification{&BaseSpecification{}}
133 | a.Relate(a)
134 | return a
135 | }
136 |
137 | // Three notices have been sent to the customer
138 | type NoticeSentSpecification struct {
139 | Specification
140 | }
141 |
142 | // Check specification
143 | func (self *NoticeSentSpecification) IsSatisfiedBy(elm Invoice) bool {
144 | return elm.Notice >= 3
145 | }
146 |
147 | // Constructor
148 | func NewNoticeSentSpecification() Specification {
149 | a := &NoticeSentSpecification{&BaseSpecification{}}
150 | a.Relate(a)
151 | return a
152 | }
153 |
154 | // Invoice has already been sent to the collection agency.
155 | type InCollectionSpecification struct {
156 | Specification
157 | }
158 |
159 | // Check specification
160 | func (self *InCollectionSpecification) IsSatisfiedBy(elm Invoice) bool {
161 | return !elm.IsSent
162 | }
163 |
164 | // Constructor
165 | func NewInCollectionSpecification() Specification {
166 | a := &InCollectionSpecification{&BaseSpecification{}}
167 | a.Relate(a)
168 | return a
169 | }
170 |
--------------------------------------------------------------------------------
/Unsorted/Specification/specification_test.go:
--------------------------------------------------------------------------------
1 | package specification
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestSpecification(t *testing.T) {
8 | overDue := NewOverDueSpecification()
9 | noticeSent := NewNoticeSentSpecification()
10 | inCollection := NewInCollectionSpecification()
11 |
12 | sendToCollection := overDue.And(noticeSent).And(inCollection.Not())
13 |
14 | invoice := Invoice{
15 | Day: 31, // >= 30
16 | Notice: 4, // >= 3
17 | IsSent: false, // false
18 | }
19 |
20 | // true!
21 | result := sendToCollection.IsSatisfiedBy(invoice)
22 |
23 | if !result {
24 | t.Errorf("Expect result to equal %v, but %v.\n", false, true)
25 | }
26 | }
27 |
--------------------------------------------------------------------------------