forked from steger/pr3-ws202526
composite design pattern
parent
9693f5027b
commit
d2f3dbd2f2
|
|
@ -0,0 +1,3 @@
|
||||||
|
module gitty.informatik.hs-mannheim.de/steger/pr3-code/go/04-design-pattern
|
||||||
|
|
||||||
|
go 1.25.0
|
||||||
|
|
@ -0,0 +1,81 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"gitty.informatik.hs-mannheim.de/steger/pr3-code/go/04-design-pattern/patterns"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ConstValueCalculator float64
|
||||||
|
|
||||||
|
func NewConstValueCalculator(valueString string) *ConstValueCalculator {
|
||||||
|
var value float64
|
||||||
|
if _, err := fmt.Sscanf(valueString, "%f", &value); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
cvc := ConstValueCalculator(value)
|
||||||
|
return &cvc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ConstValueCalculator) Calc() float64 {
|
||||||
|
return float64(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
parses the expression and builds a binary calculation tree. Returns the tree, the remaining expression after parsing, and an error
|
||||||
|
|
||||||
|
example Input:
|
||||||
|
1. [2] => 2
|
||||||
|
2. [+ 2 3] => 5
|
||||||
|
3. [* 2 3] => 6
|
||||||
|
4. [+ * 2 3 4] == [+ 6 4] => 10
|
||||||
|
*/
|
||||||
|
func buildBinaryCalculationTree(expression []string) (patterns.Calculator, []string, error) {
|
||||||
|
|
||||||
|
if len(expression) == 0 {
|
||||||
|
return nil, nil, fmt.Errorf("empty argument")
|
||||||
|
}
|
||||||
|
|
||||||
|
//1. attempt: try a composite calculator from an operator
|
||||||
|
composite := patterns.NewCompositeCalculatorFromOperator(expression[0])
|
||||||
|
if composite != nil {
|
||||||
|
expression = expression[1:]
|
||||||
|
for i := 0; i < 2; i++ {
|
||||||
|
arg, remaining, err := buildBinaryCalculationTree(expression)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
expression = remaining
|
||||||
|
composite.Add(arg)
|
||||||
|
}
|
||||||
|
return composite, expression, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//2. attempt: try a const value calculator from a value
|
||||||
|
constValue := NewConstValueCalculator(expression[0])
|
||||||
|
if constValue != nil {
|
||||||
|
return constValue, expression[1:], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//3. failure, no valid symbol
|
||||||
|
return nil, nil, fmt.Errorf("invalid symbol: %s", expression[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
// run for example with go run . + "*" 2 2 4
|
||||||
|
// note the "*" because * would otherwise expand
|
||||||
|
func main() {
|
||||||
|
calc, remainingArgs, err := buildBinaryCalculationTree(os.Args[1:])
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(remainingArgs) != 0 {
|
||||||
|
fmt.Println("Invalid Input - remaining arguments", remainingArgs)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(calc.Calc())
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
package patterns
|
||||||
|
|
||||||
|
type Calculator interface {
|
||||||
|
Calc() float64
|
||||||
|
}
|
||||||
|
|
||||||
|
type Aggregator func(float64, float64) float64
|
||||||
|
|
||||||
|
type CompositeCalculator struct {
|
||||||
|
initialValue float64
|
||||||
|
aggregator Aggregator
|
||||||
|
children []Calculator
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ Calculator = CompositeCalculator{}
|
||||||
|
|
||||||
|
func NewCompositeCalculator(initialValue float64, aggregator Aggregator) *CompositeCalculator {
|
||||||
|
return &CompositeCalculator{initialValue, aggregator, nil}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCompositeCalculatorFromOperator(operator string) *CompositeCalculator {
|
||||||
|
switch operator {
|
||||||
|
case "+":
|
||||||
|
return NewCompositeCalculator(0.0, func(a, b float64) float64 { return a + b })
|
||||||
|
case "*":
|
||||||
|
return NewCompositeCalculator(1.0, func(a, b float64) float64 { return a * b })
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c CompositeCalculator) Calc() float64 {
|
||||||
|
result := c.initialValue
|
||||||
|
for _, child := range c.children {
|
||||||
|
result = c.aggregator(result, child.Calc())
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CompositeCalculator) Add(child Calculator) {
|
||||||
|
c.children = append(c.children, child)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
package patterns_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"gitty.informatik.hs-mannheim.de/steger/pr3-code/go/04-design-pattern/patterns"
|
||||||
|
)
|
||||||
|
|
||||||
|
type valueCalc float64
|
||||||
|
|
||||||
|
func (v valueCalc) Calc() float64 {
|
||||||
|
return float64(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCompositeCalculator_Empty(t *testing.T) {
|
||||||
|
empty := patterns.NewCompositeCalculator(5.0, func(a, b float64) float64 { return a + b })
|
||||||
|
got := empty.Calc()
|
||||||
|
want := 5.0
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("Empty: got %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCompositeCalculator_Addition(t *testing.T) {
|
||||||
|
add := patterns.NewCompositeCalculatorFromOperator("+")
|
||||||
|
add.Add(valueCalc(5))
|
||||||
|
add.Add(valueCalc(3))
|
||||||
|
add.Add(valueCalc(2))
|
||||||
|
got := add.Calc()
|
||||||
|
want := 10.0
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("Addition: got %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCompositeCalculator_Multiplication(t *testing.T) {
|
||||||
|
mul := patterns.NewCompositeCalculatorFromOperator("*")
|
||||||
|
mul.Add(valueCalc(2))
|
||||||
|
mul.Add(valueCalc(3))
|
||||||
|
mul.Add(valueCalc(4))
|
||||||
|
got := mul.Calc()
|
||||||
|
want := 24.0
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("Multiplication: got %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCompositeCalculator_Nested(t *testing.T) {
|
||||||
|
// + 5 3 2 * 2 3 + 4 4 = 5 + 3 + 2 + (2 * 3 * (4+4)) = 5+3+2+48 = 58
|
||||||
|
add := patterns.NewCompositeCalculatorFromOperator("+")
|
||||||
|
add.Add(valueCalc(5))
|
||||||
|
add.Add(valueCalc(3))
|
||||||
|
add.Add(valueCalc(2))
|
||||||
|
|
||||||
|
mul := patterns.NewCompositeCalculatorFromOperator("*")
|
||||||
|
mul.Add(valueCalc(2))
|
||||||
|
mul.Add(valueCalc(3))
|
||||||
|
|
||||||
|
add2 := patterns.NewCompositeCalculatorFromOperator("+")
|
||||||
|
add2.Add(valueCalc(4))
|
||||||
|
add2.Add(valueCalc(4))
|
||||||
|
|
||||||
|
mul.Add(add2)
|
||||||
|
add.Add(mul)
|
||||||
|
|
||||||
|
got := add.Calc()
|
||||||
|
want := 58.0
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("Nested: got %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue