Skip to content

Commit 3442be5

Browse files
committed
Merge branch 'visitor'
2 parents e23716b + c5a9e76 commit 3442be5

File tree

4 files changed

+187
-0
lines changed

4 files changed

+187
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
* [Memento](behavioral/memento) [:notebook:](https://en.wikipedia.org/wiki/Memento_pattern)
1313
* [Strategy](behavioral/strategy) [:notebook:](https://en.wikipedia.org/wiki/Strategy_pattern)
1414
* [Template](behavioral/template) [:notebook:](https://en.wikipedia.org/wiki/Template_pattern)
15+
* [Visitor](behavioral/visitor) [:notebook:](https://en.wikipedia.org/wiki/Visitor_pattern)
1516

1617
## [Creational](creational)
1718

behavioral/visitor/README.md

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
# Visitor
2+
3+
The visitor pattern is a way to separate algorithm from an object structure. It is one way to implement the open/closed principle of SOLID. It allows to add functionalities without object modification. A visitor take the object instance as input and implements the algorithm.
4+
5+
## Implementation
6+
7+
In the following implementation we will create a visitor that will visit all cards inside a project. Each card represents a Task or a Bug. Each card contains a title and some points. Here, card is an interface that for simplicity implement just a part of a complete card.
8+
9+
Let's start from the card interface. Each card will contains, at least, GetTitle() and GetPoints() method. In a real world example each card could contains more and more specific methods. This is just a trivial example.
10+
11+
```go
12+
type Card interface {
13+
GetTitle() string
14+
GetPoints() int
15+
}
16+
```
17+
18+
Now let's implement both task and bug object within interface Card.
19+
20+
```go
21+
type Task struct {
22+
Title string
23+
Time int
24+
}
25+
26+
func (b *Task) GetTitle() string {
27+
return b.Title
28+
}
29+
30+
func (b *Task) GetPoints() int {
31+
return b.Time
32+
}
33+
34+
type Bug struct {
35+
Title string
36+
Time int
37+
}
38+
39+
func (b *Bug) GetTitle() string {
40+
return b.Title
41+
}
42+
43+
func (b *Bug) GetPoints() int {
44+
return b.Time
45+
}
46+
```
47+
48+
Until now we have not yet visitor pattern elements. We just have bugs and tasks. In the visitor pattern there always be `Visitable` and `Visitor` items. Our visitor will visit a card. All visitable item must accecpt a visitor.
49+
50+
```go
51+
type Visitable interface {
52+
Accept(v Visitor)
53+
}
54+
55+
type Visitor interface {
56+
Visit(t Card)
57+
}
58+
```
59+
60+
Now we want that alla cards are visitable.
61+
62+
```go
63+
func (b *Task) Accept(v Visitor) {
64+
v.Visit(b)
65+
}
66+
67+
func (b *Bug) Accept(v Visitor) {
68+
v.Visit(b)
69+
}
70+
```
71+
72+
And here we have the visitor: a service that sum each cards points. As we can see the logic is not in Bug object nor in Task.
73+
74+
```go
75+
type EstimationVisitor struct {
76+
Sum int
77+
}
78+
79+
func (e *EstimationVisitor) Visit(t Card) {
80+
e.Sum += t.GetPoints()
81+
}
82+
```
83+
84+
Finally, the main function, where it is visible the Visitor in action.
85+
86+
```go
87+
func main() {
88+
nextRelease := []Visitable{
89+
&Task{"Do stuff", 1},
90+
&Task{"Implement Foo Bar", 5},
91+
&Bug{"Error 500 on resource /foo/bar", 3},
92+
}
93+
94+
storyPoint := new(EstimationVisitor)
95+
96+
for _, i := range nextRelease {
97+
i.Accept(storyPoint)
98+
}
99+
100+
// "Next release is calulated in 9 story points"
101+
fmt.Println(
102+
"Next release is calulated in",
103+
storyPoint.Sum,
104+
"story points",
105+
)
106+
}
107+
```

behavioral/visitor/visitor.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package main
2+
3+
import "fmt"
4+
5+
type Card interface {
6+
GetTitle() string
7+
GetPoints() int
8+
}
9+
10+
type Visitable interface {
11+
Accept(v Visitor)
12+
}
13+
14+
type Task struct {
15+
Title string
16+
Time int
17+
}
18+
19+
func (b *Task) GetTitle() string {
20+
return b.Title
21+
}
22+
23+
func (b *Task) GetPoints() int {
24+
return b.Time
25+
}
26+
27+
func (b *Task) Accept(v Visitor) {
28+
v.Visit(b)
29+
}
30+
31+
type Bug struct {
32+
Title string
33+
Time int
34+
}
35+
36+
func (b *Bug) GetTitle() string {
37+
return b.Title
38+
}
39+
40+
func (b *Bug) GetPoints() int {
41+
return b.Time
42+
}
43+
44+
func (b *Bug) Accept(v Visitor) {
45+
v.Visit(b)
46+
}
47+
48+
type Visitor interface {
49+
Visit(t Card)
50+
}
51+
52+
type EstimationVisitor struct {
53+
Sum int
54+
}
55+
56+
func (e *EstimationVisitor) Visit(t Card) {
57+
e.Sum += t.GetPoints()
58+
}
59+
60+
func main() {
61+
nextRelease := []Visitable{
62+
&Task{"Do stuff", 1},
63+
&Task{"Implement Foo Bar", 5},
64+
&Bug{"Error 500 on resource /foo/bar", 3},
65+
}
66+
67+
storyPoint := new(EstimationVisitor)
68+
69+
for _, i := range nextRelease {
70+
i.Accept(storyPoint)
71+
}
72+
73+
fmt.Println(
74+
"Next release is calulated in",
75+
storyPoint.Sum,
76+
"story points",
77+
)
78+
}

structural/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ relationships.
1212
* [Decorator](decorator) [:notebook:](https://en.wikipedia.org/wiki/Decorator_pattern)
1313
* [Flyweight](flyweight) [:notebook:](https://en.wikipedia.org/wiki/Flyweight_pattern)
1414
* [Proxy](proxy) [:notebook:](https://en.wikipedia.org/wiki/Proxy_pattern)
15+
* [Visitor](visitor) [:notebook:](https://en.wikipedia.org/wiki/Visitor_pattern)

0 commit comments

Comments
 (0)