Skip to content

Commit 080b91e

Browse files
committed
add flyweight pattern
1 parent 1f3fd18 commit 080b91e

File tree

7 files changed

+222
-2
lines changed

7 files changed

+222
-2
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@
1616
* [Bridge](structural/bridge) [:notebook:](https://en.wikipedia.org/wiki/Bridge_pattern)
1717
* [Composite](structural/composite) [:notebook:](http://en.wikipedia.org/wiki/Composite_pattern)
1818
* [Decorator](structural/decorator) [:notebook:](https://en.wikipedia.org/wiki/Decorator_pattern)
19+
* [Flyweight](structural/flyweight) [:notebook:](https://en.wikipedia.org/wiki/Flyweight)
1920
* [Proxy](structural/proxy) [:notebook:](https://en.wikipedia.org/wiki/Proxy_pattern)

creational/README.md

+12-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
11
# Creational patterns
22

3-
Some patterns can overlap a bit. Use them with care and in the right context. Remember that these patterns's purpose is to abstract the creation of objects for complexity and maintenance purpose.
3+
Some patterns can overlap a bit. Use them with care and in the right context.
4+
Remember that these patterns's purpose is to abstract the creation of objects
5+
for complexity and maintenance purpose.
6+
7+
## [Creational](creational)
8+
9+
* [Abstract Factory method](creational/abstract_factory) [:notebook:](http://en.wikipedia.org/wiki/Abstract_Factory_pattern)
10+
* [Builder](creational/builder) [:notebook:](http://en.wikipedia.org/wiki/Builder_pattern)
11+
* [Factory method](creational/factory) [:notebook:](http://en.wikipedia.org/wiki/Factory_pattern)
12+
* [Object Pool](creational/pool) [:notebook:](http://en.wikipedia.org/wiki/Object_Pool_pattern)
13+
* [Prototype](creational/prototype) [:notebook:](http://en.wikipedia.org/wiki/Prototype_pattern)
14+
* [Singleton](creational/singleton) [:notebook:](http://en.wikipedia.org/wiki/Singleton_pattern) (is considered an anti-pattern! :no_entry:)

runtests.sh

+1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
#!/bin/bash
22
go test ./creational/...
3+
go test ./structural/...

structural/README.md

+12-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
11
# Structural Patterns
22

3-
Structural patterns help us to shape application with common used structures and relationships.
3+
Structural patterns help us to shape application with common used structures and
4+
relationships.
5+
6+
## [Structural](structural)
7+
8+
* [Adapter](structural/adapter) [:notebook:](https://en.wikipedia.org/wiki/Adapter_pattern)
9+
* [Binary Tree compositions](structural/binary-tree-compositions) [:notebook:](https://en.wikipedia.org/wiki/Binary_tree)
10+
* [Bridge](structural/bridge) [:notebook:](https://en.wikipedia.org/wiki/Bridge_pattern)
11+
* [Composite](structural/composite) [:notebook:](http://en.wikipedia.org/wiki/Composite_pattern)
12+
* [Decorator](structural/decorator) [:notebook:](https://en.wikipedia.org/wiki/Decorator_pattern)
13+
* [Flyweight](structural/flyweight) [:notebook:](https://en.wikipedia.org/wiki/Flyweight)
14+
* [Proxy](structural/proxy) [:notebook:](https://en.wikipedia.org/wiki/Proxy_pattern)

structural/flyweight/README.md

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# Flyweight
2+
3+
This pattern it's very commonly used in computer graphics and the video game
4+
industry. It allow sharing the state of a heavy object between many instances of
5+
some type.
6+
7+
This example uses a creational pattern to create objects instance.
8+
9+
```go
10+
func TestFactoryCreatesObjects(t *testing.T) {
11+
f := NewObjectFactory()
12+
firstObject := f.GetObject(TYPE_ONE)
13+
if firstObject == nil {
14+
t.Error("The pointer to the TYPE_ONE was nil")
15+
}
16+
}
17+
18+
```
19+
20+
According to the flyweight pattern, each object requested is returned. Well,
21+
what is really returned is not an object but a pointer to that object.
22+
23+
```go
24+
func TestFactoryCreatesTwoObjects(t *testing.T) {
25+
f := NewObjectFactory()
26+
_ = f.GetObject(TYPE_ONE)
27+
secondObject := f.GetObject(TYPE_ONE)
28+
if secondObject == nil {
29+
t.Error("The pointer to the TYPE_ONE was nil")
30+
}
31+
}
32+
33+
```
34+
35+
Each pointer created is a different pointer.
36+
37+
```go
38+
func TestFactoryCreatesJustObjectOfTypes(t *testing.T) {
39+
f := NewObjectFactory()
40+
firstObject := f.GetObject(TYPE_ONE)
41+
secondObject := f.GetObject(TYPE_ONE)
42+
if firstObject != secondObject {
43+
t.Error("TYPE_ONE pointers weren't the same")
44+
}
45+
}
46+
47+
```
48+
49+
Even if object of TYPE_ONE is requested more times, the number of created
50+
objects is equals to the number of type requested.
51+
52+
```go
53+
func TestNumberOfObjectsIsAlwaysNumberOfTypeOfObjectCreated(t *testing.T) {
54+
f := NewObjectFactory()
55+
_ = f.GetObject(TYPE_ONE)
56+
_ = f.GetObject(TYPE_ONE)
57+
if f.GetNumberOfObjects() != 1 {
58+
t.Errorf(
59+
"The number of objects created was not 1: %d\n",
60+
f.GetNumberOfObjects(),
61+
)
62+
}
63+
}
64+
65+
```
66+
67+
Finally, and for completeness, if two objects are requested a huge amount of
68+
time, the number of object created is still two.
69+
70+
```go
71+
func TestHighVolume(t *testing.T) {
72+
f := NewObjectFactory()
73+
objects := make([]*Object, 500000*2)
74+
for i := 0; i < 500000; i++ {
75+
objects[i] = f.GetObject(TYPE_ONE)
76+
}
77+
for i := 500000; i < 2*500000; i++ {
78+
objects[i] = f.GetObject(TYPE_TWO)
79+
}
80+
if f.GetNumberOfObjects() != 2 {
81+
t.Errorf(
82+
"The number of objects created was not 2: %d\n",
83+
f.GetNumberOfObjects(),
84+
)
85+
}
86+
}
87+
```

structural/flyweight/flyweight.go

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package flyweight
2+
3+
const (
4+
TYPE_ONE = iota
5+
TYPE_TWO
6+
)
7+
8+
type Object struct {
9+
ID uint64
10+
Name int
11+
}
12+
13+
type objectFactory struct {
14+
createdObjects map[int]*Object
15+
}
16+
17+
func (f *objectFactory) GetObject(objectID int) *Object {
18+
if f.createdObjects[objectID] != nil {
19+
return f.createdObjects[objectID]
20+
}
21+
object := getObjectFactory(objectID)
22+
f.createdObjects[objectID] = &object
23+
return f.createdObjects[objectID]
24+
}
25+
26+
func (f *objectFactory) GetNumberOfObjects() int {
27+
return len(f.createdObjects)
28+
}
29+
30+
func getObjectFactory(object int) Object {
31+
switch object {
32+
case TYPE_TWO:
33+
return Object{
34+
ID: 2,
35+
Name: TYPE_TWO,
36+
}
37+
default:
38+
return Object{
39+
ID: 1,
40+
Name: TYPE_ONE,
41+
}
42+
}
43+
}
44+
45+
func NewObjectFactory() objectFactory {
46+
return objectFactory{
47+
createdObjects: make(map[int]*Object),
48+
}
49+
}
+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package flyweight
2+
3+
import (
4+
"testing"
5+
)
6+
7+
func TestFactoryCreatesObjects(t *testing.T) {
8+
f := NewObjectFactory()
9+
firstObject := f.GetObject(TYPE_ONE)
10+
if firstObject == nil {
11+
t.Error("The pointer to the TYPE_ONE was nil")
12+
}
13+
}
14+
15+
func TestFactoryCreatesTwoObjects(t *testing.T) {
16+
f := NewObjectFactory()
17+
_ = f.GetObject(TYPE_ONE)
18+
secondObject := f.GetObject(TYPE_ONE)
19+
if secondObject == nil {
20+
t.Error("The pointer to the TYPE_ONE was nil")
21+
}
22+
}
23+
24+
func TestFactoryCreatesJustObjectOfTypes(t *testing.T) {
25+
f := NewObjectFactory()
26+
firstObject := f.GetObject(TYPE_ONE)
27+
secondObject := f.GetObject(TYPE_ONE)
28+
if firstObject != secondObject {
29+
t.Error("TYPE_ONE pointers weren't the same")
30+
}
31+
}
32+
33+
func TestNumberOfObjectsIsAlwaysNumberOfTypeOfObjectCreated(t *testing.T) {
34+
f := NewObjectFactory()
35+
_ = f.GetObject(TYPE_ONE)
36+
_ = f.GetObject(TYPE_ONE)
37+
if f.GetNumberOfObjects() != 1 {
38+
t.Errorf(
39+
"The number of objects created was not 1: %d\n",
40+
f.GetNumberOfObjects(),
41+
)
42+
}
43+
}
44+
45+
func TestHighVolume(t *testing.T) {
46+
f := NewObjectFactory()
47+
objects := make([]*Object, 500000*2)
48+
for i := 0; i < 500000; i++ {
49+
objects[i] = f.GetObject(TYPE_ONE)
50+
}
51+
for i := 500000; i < 2*500000; i++ {
52+
objects[i] = f.GetObject(TYPE_TWO)
53+
}
54+
if f.GetNumberOfObjects() != 2 {
55+
t.Errorf(
56+
"The number of objects created was not 2: %d\n",
57+
f.GetNumberOfObjects(),
58+
)
59+
}
60+
}

0 commit comments

Comments
 (0)