DEV Community

Preston Pham
Preston Pham

Posted on • Originally published at Medium on

Design Pattern: Composite

A colorful painting of a gift box of mangos, in the style of 1800s, pixel art

We can consider a single type or a composition of related types to be the same by:

  • Creating a new type, usually an interface, to represent them, called Component.
  • Allowing recursive structure, meaning Component can contain other child Components. Components within this structure are called Composite , while those without any children are called Leaf.

When to Use

  1. When representing hierarchical systems.
  2. When disregarding the difference between a single object and a composition of objects, treating them all as a Component.

Implementation

Structure

Let's take the example of a UI framework (something like React). UIComponent represents all types of components such as buttons, text, etc. We also have Popup, which is a more complex component, composed of a button and a text, making it a Composite.

Sample Code

Component interface:

type UIComponent interface {
  Render()
}
Enter fullscreen mode Exit fullscreen mode

Some *Leaf * types:

type Text struct{}
func (t *Text) Render() {
  fmt.Print("hello")
}

type Button struct{}
func (b *Button) Render() {
  fmt.Print("button: ")
}
Enter fullscreen mode Exit fullscreen mode

Composite:

type Popup struct {
  children []UIComponent
}

func (p *Popup) Render() {
  for _, c := range p.children {
    c.Render()
  }
}
Enter fullscreen mode Exit fullscreen mode

Usage:

text := &Text{}
button := &Button{}
popup := &Popup{
  children: []UIComponent{button, text},
}
popup.Render()

// Output:
// button: hello
Enter fullscreen mode Exit fullscreen mode

This pattern offers a way to treat individual objects and compositions uniformly, providing a unified way to work with both. Moreover, we can freely switch the types behind UIComponent interface without affecting the users.

Testing

This is a pure pattern for building a structure, so I think we can skip this part 😇

Related patterns

Chain Of Responsibility

If we add the parent UIComponent field to UIComponent interface, we can create a usable structure for the Chain Of Responsibility pattern. Check out the pattern's article for more details.

Iterator

Iterator can be used to iterate through each component in the Composite structure.

Visitor

Helps gather the logic of the components in one place instead of being scattered across Composites and Leaves.

Decorator

Often used in conjunction with Composite. Check out the Decorator Pattern for more details.


Top comments (0)