# Composite Pattern

The composite design pattern allows us to create a tree structure of objects. The key idea with the pattern is that given a root component, we can access all nodes in the structure. Such access is granted using a common interface that refers to either of two object types:

* Leaf - a primitive object
    
* Composite - a group of component objects
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1681329559741/e08f9872-3e6f-4178-bf74-4aed60f21799.jpeg align="center")

We (mostly) do not care which underlying object type the interface is representing but we can always find out if need be (*see bonus example section*). As shown in the diagram above, the *component* is the common interface for accessing the structure. A *composite* stores instances of child components -- either leaves or other composites.

With the composite pattern, you only need a reference to the root component and with it, you have access to the rest of the tree. Let us look at an implementation of this pattern in Android.

## The Android View(Group)

From the Android docs on [View](https://developer.android.com/reference/android/view/View) and [ViewGroup](https://developer.android.com/reference/android/view/ViewGroup), we derive a visualization similar to the one above:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1681760037067/ddf3d78b-7bff-41ae-926d-f6f50ee3b2ba.jpeg align="center")

> * `View` is the base class for building UI elements (the *component*)
>     
> * A widget is a view representing an interactive UI component (a *leaf*)
>     
> * A `Viewgroup` is a view representing a container component to hold other `View`s (the *composite*)
>     

We use the relationship described here to create rich Android UIs, comprised of a hierarchy of `View`s. A subtle but important consequence is that each layout is referenced through a single `View` instance i.e. the root node of the view tree structure. The Activity class provides a `setContentView` api that accepts a root `View` instance for representing its UI.

```kotlin
class TheActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Some inflated view e.g. using viewbinding
        val rootView: View = ...

        setContentView(rootView)
    }
}
```

The `View` argument to the `setContentView` method could be representing a one-button UI or a whole suite of widget combinations in a UI hierarchy. All the Activity requires is a reference to the root of the view hierarchy.

Consider two xml-based layouts. One has a **TextView** as the only view component in the layout and the other, a **ConstraintLayout** (a *ViewGroup*) that contains a **TextView**. Inflating each of these layouts in an Activity, we visually get the same UI.

```xml
<!-- activity_ui_with_single_widget.xml -->

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/textView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:text="@string/app_name"
    android:textSize="@dimen/textSize"
    tools:context=".MainActivity" />
```

```xml
<!-- activity_ui_with_viewgroup -->

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/textView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/app_name"
        android:textSize="@dimen/textSize"
        android:gravity="center"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
```

To render a UI on the screen, the Android framework invokes methods in the `View` class such as `onMeasure` and `onDraw`. These invocations are then dispatched accordingly to all nodes in the tree structure; either to a **Widget** or a **ViewGroup**. This is the composite design pattern in use.

## A bonus example

For a bonus example of the composite pattern, let's model a hypothetical representation for a filesystem. (You can find a more robust design in the [Java IO package](https://docs.oracle.com/javase/7/docs/api/java/io/File.html))

A file in our design can be represented as follows:

```kotlin
sealed interface File {
    val name: String
}
```

`File` is the common interface as laid out in the pattern. We'll keep this interface simple by ignoring other typical file attributes e.g. permissions, extension etc.

For the basic filesystem elements, our design allows for two types of files - a *normal* and a *directory* file.

```kotlin
class Normal(override val name: String) : File

class Directory(
    override val name: String,
    private val files: MutableList<File> = mutableListOf()
) : File, MutableCollection<File> by files
```

A *normal* file's definition is trivial, overriding the required *name* property as a constructor parameter to conform to the `File` contract.

The *directory* file is a tad bit involved but conveniently expressible using [Kotlin](https://kotlinlang.org/). We start by overriding the required *name* property as a constructor parameter. Since a directory is a mutable collection of other `File`s, we model it using the `MutableCollection` interface and delegate the collection's implementation to a `MutableList` instance. The list instance also facilitates the actual storage of `File` entries.

The relationship for `File`, `Normal` and `Directory` can be viewed as follows:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1681760048602/d381d8b3-debb-460a-96af-2828f2c30cb6.jpeg align="center")

If we are tasked with printing all files for a sample filesystem shown below, our use of the composite design makes it straightforward.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1681760057879/261e600c-8e5f-4b81-94b6-f2da90cf0041.jpeg align="center")

Given a starting directory, here's a typical `walk` implementation:

```kotlin
fun walk(file: File, printer: Printer) {
    if (file !is Directory) return // runtime-type-check
    
    for (child in file) {
        printer.print(child)
        walk(child, printer)
    }
}
```

The `walk` method takes as arguments a `File` instance and a `Printer`. In Kotlin, we can [check the type](https://kotlinlang.org/docs/typecasts.html) represented by a `File` instance at runtime using the `is` operator. This allows for an early return in the method by ignoring `Normal` files during a recursion as they are not iterable. Each child file in a directory is then printed and then we recurse. Can you work out the output of this algorithm?

```kotlin
fun interface Printer {
    fun print(file: File)
}
```

Using the `File` type for our printing method, as shown above, we can print any `File` instance - whether a *normal* or *directory* file - as [Liskov Substitution principle](https://en.wikipedia.org/wiki/Liskov_substitution_principle) applies. Therefore, given a root directory file, we get access to all files in the tree structure thanks to the composite pattern.

## Conclusion

The composite design pattern is useful for modeling a tree structure where individual objects and composites are treated uniformly. Given a handle to the root node, you can act on all nodes in the structure. This pattern occurs time and again in written software and is a good addition to your software architecture toolbelt.

Happy coding!

Thanks, [Ali](https://www.linkedin.com/in/ali-ziwa/) for your review and suggestions.
