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) }