liveBook · Manning

Composition over inheritance

As explained in Go in Action, Second Edition

Composition over inheritance is a design pattern that builds complex types by combining simpler components instead of deriving them from superclasses.

Composition over inheritance builds complex Go types by combining simpler components rather than deriving them from superclasses. This supports type-safe, expressive, and maintainable domain models. section 5.0

A Go implementation combines:

Recipe application

A recipe model composes measurements, ingredients, steps, and recipes. Interfaces and methods support scaling recipes, converting measurement systems, summarizing recipes, and creating grocery lists. section 5.0 section 5.6.2

// Example usage in main.
func main() {
    recipe := Recipe{
        Title: "Pancakes",
        Yield: 2,
    }
    recipe.AddStep(Step{ #1
        Description: "Mix dry ingredients",
        Ingredients: []IngredientMeasurement{
            {"Flour", MetricWeight{Measurement{Magnitude: 200, Unit: Gram}}},
            {"Sugar", MetricWeight{Measurement{Magnitude: 50, Unit: Gram}}},
        },
    })
    recipe.AddStep(Step{ #2
        Description: "Add wet ingredients",
        Ingredients: []IngredientMeasurement{
            {"Milk", MetricWeight{Measurement{Magnitude: 300, Unit: Gram}}},
            {"Egg", MetricWeight{Measurement{Magnitude: 50, Unit: Gram}}},
        },
    })

    fmt.Println("Original Recipe:", recipe) #3
    recipe.Scale(2) #4
    fmt.Println("Scaled Recipe:", recipe) #5

    list := CreateGroceryList(RecipeBox{recipe}) #6
    fmt.Println("Grocery List:") #7
    for ing, meas := range list {
        fmt.Printf("%s: %.2f %s\n", ing, meas.Magnitude, meas.Unit) #8
    }
}

The runnable usage listing creates a pancake recipe, adds ingredient steps, scales the recipe, prints both versions, and generates a grocery list. section 5.6.2

How Go in Action, Second Edition covers it

How deep it goes
Explains the principle through named types, structs, embedded types, collections, interfaces, and methods, stopping at application-level examples.
Examples
Uses measurements, ingredients, recipe steps, scaling, unit conversion, recipe summaries, and grocery-list generation.
What it assumes
Assumes Go primitives, then develops named types, structs, interfaces, and composition for a domain model.
What you can do after
Build it from scratch by composing Go types and interfaces into extensible domain models with scaling and conversion behavior.
How it connects
Connects type safety, structs, embedded types, interfaces, named types, collection types, methods, and polymorphism.

Also explained in

Compare how 2 books explain composition over inheritance →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Go in Action, Second Edition. The section links point to the parts of the book it draws on.