Skip to content

Commit 878ddb9

Browse files
authored
Merge pull request mouredev#4719 from hozlucas28/Solution-27-Go
#27 - Go
2 parents 3ed047d + 7be64cd commit 878ddb9

File tree

1 file changed

+374
-0
lines changed

1 file changed

+374
-0
lines changed
Lines changed: 374 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,374 @@
1+
package main
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"math"
7+
)
8+
9+
/* -------------------------------------------------------------------------- */
10+
/* CLASSES AND INTERFACES */
11+
/* -------------------------------------------------------------------------- */
12+
13+
/* ---------------------------- BadCircle (class) --------------------------- */
14+
15+
type BadCircle struct {
16+
radius float64
17+
_ struct{}
18+
}
19+
20+
/* -------------------------- BadRectangle (class) -------------------------- */
21+
22+
type BadRectangle struct {
23+
height float64
24+
width float64
25+
_ struct{}
26+
}
27+
28+
/* -------------------------- BadCalculator (class) ------------------------- */
29+
30+
type BadCalculator struct{}
31+
32+
func (calculator BadCalculator) GetArea(shape interface{}) float64 {
33+
switch shape := shape.(type) {
34+
case BadCircle:
35+
return math.Pi * math.Pow(shape.radius, 2)
36+
37+
case BadRectangle:
38+
return shape.height * shape.width
39+
40+
default:
41+
return -1
42+
}
43+
}
44+
45+
/* ---------------------------- Shape (interface) --------------------------- */
46+
47+
type Shape interface {
48+
GetArea() float64
49+
}
50+
51+
/* --------------------------- GoodCircle (class) --------------------------- */
52+
53+
type goodCircle struct {
54+
radius float64
55+
_ struct{}
56+
}
57+
58+
func NewGoodCircle(radius float64) Shape {
59+
var circle goodCircle = goodCircle{radius: radius}
60+
return &circle
61+
}
62+
63+
func (circle *goodCircle) GetArea() float64 {
64+
return math.Pi * math.Pow(circle.radius, 2)
65+
}
66+
67+
/* -------------------------- GoodRectangle (class) ------------------------- */
68+
69+
type goodRectangle struct {
70+
height float64
71+
width float64
72+
_ struct{}
73+
}
74+
75+
func NewGoodRectangle(height float64, width float64) Shape {
76+
var rectangle goodRectangle = goodRectangle{height: height, width: width}
77+
return &rectangle
78+
}
79+
80+
func (rectangle *goodRectangle) GetArea() float64 {
81+
return rectangle.height * rectangle.width
82+
}
83+
84+
/* ------------------ GoodCalculator (class And Interface) ------------------ */
85+
86+
type IGoodCalculator interface {
87+
GetArea(shape Shape) float64
88+
}
89+
90+
type goodCalculator struct{}
91+
92+
func NewGoodCalculator() IGoodCalculator {
93+
var calculator goodCalculator = goodCalculator{}
94+
return &calculator
95+
}
96+
97+
func (calculator *goodCalculator) GetArea(shape Shape) float64 {
98+
return shape.GetArea()
99+
}
100+
101+
/* -------------------------- Operation (interface) ------------------------- */
102+
103+
type Operation interface {
104+
Execute(a float64, b float64) (float64, error)
105+
}
106+
107+
/* -------------------------- AddOperation (class) -------------------------- */
108+
109+
type addOperation struct{}
110+
111+
func NewAddOperation() Operation {
112+
var add addOperation = addOperation{}
113+
return &add
114+
}
115+
116+
func (operation *addOperation) Execute(a float64, b float64) (float64, error) {
117+
return a + b, nil
118+
}
119+
120+
/* ------------------------- DivideOperation (class) ------------------------ */
121+
122+
type divideOperation struct{}
123+
124+
func NewDivideOperation() Operation {
125+
var divide divideOperation = divideOperation{}
126+
return &divide
127+
}
128+
129+
func (operation *divideOperation) Execute(a float64, b float64) (float64, error) {
130+
if b == 0 {
131+
return 0, errors.New("The second parameter must not be zero")
132+
}
133+
134+
return a / b, nil
135+
136+
}
137+
138+
/* ------------------------ MultiplyOperation (class) ----------------------- */
139+
140+
type multiplyOperation struct{}
141+
142+
func NewMultiplyOperation() Operation {
143+
var multiply multiplyOperation = multiplyOperation{}
144+
return &multiply
145+
}
146+
147+
func (operation *multiplyOperation) Execute(a float64, b float64) (float64, error) {
148+
return a * b, nil
149+
150+
}
151+
152+
/* -------------------------- PowOperation (class) -------------------------- */
153+
154+
type powOperation struct{}
155+
156+
func NewPowOperation() Operation {
157+
var pow powOperation = powOperation{}
158+
return &pow
159+
}
160+
161+
func (operation *powOperation) Execute(a float64, b float64) (float64, error) {
162+
return math.Pow(a, b), nil
163+
164+
}
165+
166+
/* ------------------------ SubtractOperation (class) ----------------------- */
167+
168+
type subtractOperation struct{}
169+
170+
func NewSubtractOperation() Operation {
171+
var subtract subtractOperation = subtractOperation{}
172+
return &subtract
173+
}
174+
175+
func (operation *subtractOperation) Execute(a float64, b float64) (float64, error) {
176+
return a - b, nil
177+
178+
}
179+
180+
/* ------------------------------- Calculator ------------------------------- */
181+
182+
type ICalculator interface {
183+
AddOperation(name string, operation *Operation) error
184+
ExecuteOperation(name string, a float64, b float64) (float64, error)
185+
}
186+
187+
type calculator struct {
188+
operations map[string](*Operation)
189+
_ struct{}
190+
}
191+
192+
func NewCalculator() ICalculator {
193+
var calculator calculator = calculator{operations: map[string]*Operation{}}
194+
return &calculator
195+
}
196+
197+
func (calculator *calculator) AddOperation(name string, operation *Operation) error {
198+
_, operationExist := calculator.operations[name]
199+
if operationExist {
200+
return fmt.Errorf("The operation with '%s' name already exist", name)
201+
}
202+
203+
calculator.operations[name] = operation
204+
return nil
205+
}
206+
207+
func (calculator *calculator) ExecuteOperation(name string, a float64, b float64) (float64, error) {
208+
operation, operationExist := calculator.operations[name]
209+
if !operationExist {
210+
return 0, fmt.Errorf("There is not operation with '%s' name", name)
211+
}
212+
213+
operationResult, err := (*operation).Execute(a, b)
214+
if err != nil {
215+
return 0, err
216+
}
217+
218+
return operationResult, nil
219+
}
220+
221+
/* -------------------------------------------------------------------------- */
222+
/* MAIN */
223+
/* -------------------------------------------------------------------------- */
224+
225+
func main() {
226+
/*
227+
Open-Close Principle (OCP)...
228+
*/
229+
230+
fmt.Println("Open-Close Principle (OCP)...")
231+
232+
fmt.Println("\nBad implementation of Open-Close Principle (OCP)...")
233+
234+
fmt.Println("\n```\n" + `type BadCircle struct {
235+
radius float64
236+
_ struct{}
237+
}
238+
239+
type BadRectangle struct {
240+
height float64
241+
width float64
242+
_ struct{}
243+
}
244+
245+
type BadCalculator struct{}
246+
247+
func (calculator BadCalculator) GetArea(shape interface{}) float64 {
248+
switch shape := shape.(type) {
249+
case BadCircle:
250+
return math.Pi * math.Pow(shape.radius, 2)
251+
252+
case BadRectangle:
253+
return shape.height * shape.width
254+
255+
default:
256+
return -1
257+
}
258+
}` + "\n```")
259+
260+
fmt.Println(
261+
"\nThis is a bad implementation of Open-Close Principle (OCP),\n" +
262+
"because the method 'getArea' of struct 'BadCalculator' will must\n" +
263+
"change if we have to add more shapes types.",
264+
)
265+
266+
fmt.Println("\nGood implementation of Open-Close Principle (OCP)...")
267+
268+
fmt.Println("\n```\n" + `type Shape interface {
269+
GetArea() float64
270+
}
271+
272+
type goodCircle struct {
273+
radius float64
274+
_ struct{}
275+
}
276+
277+
func NewGoodCircle(radius float64) Shape {
278+
var circle goodCircle = goodCircle{radius: radius}
279+
return &circle
280+
}
281+
282+
func (circle *goodCircle) GetArea() float64 {
283+
return math.Pi * math.Pow(circle.radius, 2)
284+
}
285+
286+
type goodRectangle struct {
287+
height float64
288+
width float64
289+
_ struct{}
290+
}
291+
292+
func NewGoodRectangle(height float64, width float64) Shape {
293+
var rectangle goodRectangle = goodRectangle{height: height, width: width}
294+
return &rectangle
295+
}
296+
297+
func (rectangle *goodRectangle) GetArea() float64 {
298+
return rectangle.height * rectangle.width
299+
}
300+
301+
type IGoodCalculator interface {
302+
GetArea(shape Shape) float64
303+
}
304+
305+
type goodCalculator struct{}
306+
307+
func NewGoodCalculator() IGoodCalculator {
308+
var calculator goodCalculator = goodCalculator{}
309+
return &calculator
310+
}
311+
312+
func (calculator *goodCalculator) GetArea(shape Shape) float64 {
313+
return shape.GetArea()
314+
}` + "\n```")
315+
316+
fmt.Println(
317+
"\nThis is a good implementation of Open-Close Principle (OCP),\n" +
318+
"because the method 'getArea' of struct 'GoodCalculator' will must\n" +
319+
"not change if we have to add more shapes. So, 'getArea' is closed to modification\n" +
320+
"but it is open to extension throw any shape which implements 'Shape' interface.",
321+
)
322+
323+
fmt.Println(
324+
"\n# ---------------------------------------------------------------------------------- #",
325+
)
326+
327+
/*
328+
Additional challenge...
329+
*/
330+
331+
fmt.Println("\nAdditional challenge...")
332+
333+
fmt.Println("\nTesting the OCP system without a pow operation...")
334+
335+
var calculator ICalculator = NewCalculator()
336+
337+
var addOperation Operation = NewAddOperation()
338+
var divideOperation Operation = NewDivideOperation()
339+
var multiplyOperation Operation = NewMultiplyOperation()
340+
var subtractOperation Operation = NewSubtractOperation()
341+
342+
calculator.AddOperation("add", &addOperation)
343+
calculator.AddOperation("add", &divideOperation)
344+
calculator.AddOperation("multiply", &multiplyOperation)
345+
calculator.AddOperation("subtract", &subtractOperation)
346+
347+
var a float64 = 11
348+
var b float64 = 8.2
349+
350+
addOperationResult, _ := calculator.ExecuteOperation("add", a, b)
351+
fmt.Printf("\nAdd operation result (%.2f + %.2f): %f", a, b, addOperationResult)
352+
353+
a, b = 5, 4.2
354+
divideOperationResult, _ := calculator.ExecuteOperation("divide", a, b)
355+
fmt.Printf("\nDivide operation result (%.2f / %.2f): %f", a, b, divideOperationResult)
356+
357+
a, b = 2, 6.6
358+
multiplyOperationResult, _ := calculator.ExecuteOperation("multiply", a, b)
359+
fmt.Printf("\nMultiply operation result (%.2f * %.2f): %f", a, b, multiplyOperationResult)
360+
361+
a, b = -1, -6.888
362+
subtractOperationResult, _ := calculator.ExecuteOperation("subtract", a, b)
363+
fmt.Printf("\nSubtract operation result (%.2f - %.3f): %f", a, b, subtractOperationResult)
364+
365+
fmt.Println("\n\nTesting the OCP system with a pow operation...")
366+
367+
var powOperation Operation = NewPowOperation()
368+
369+
calculator.AddOperation("pow", &powOperation)
370+
371+
a, b = 2, 10
372+
powOperationResult, _ := calculator.ExecuteOperation("pow", a, b)
373+
fmt.Printf("\nPow operation result (%.2f^%.2f): %f", a, b, powOperationResult)
374+
}

0 commit comments

Comments
 (0)