What is Composite and Builder Design Pattern

Let’s understand both of these patterns with Tree.

Rikam Palkar
Level Up Coding
Published in
4 min readFeb 22, 2022

--

The composite pattern provides a way to work with tree structures. In other words, data structures with parent/child relationships. For example, JSON, HTML, XML and so on.

In the .NET framework, XElement is developed using a composite design pattern. This pattern is so important even Microsoft is using it.

A real-world example would be the file system.

Image 1: File system

As you can see in the image above, the directory can contain multiple directories or files in it. However, files can not contain more files or directories as they are considered as leaf nodes.

The composite pattern enables clients to interact with individual objects or compositions of objects in a uniform fashion. (Composition follows “has a relationship”)

The composite pattern is not only about modeling tree structures, but in particular, enabling clients to act on those tree structures uniformly. Let’s understand what that means by our file structure example. If I want to get the size of an individual file, then I could use a method on these individual files to give me its size, and in return I would get the number of bytes of the file. But what if I want to know the size of a whole directory, say I want to get the size of Directory Blog from image 1. I just have to call a method on Directory Blog and as a consumer, I don’t want to have to worry about what’s going on through internal logic to get the total size of the directory Blog.

Conceptually, this is what the composite pattern is used for, whether I want to act upon the granular level or an individual leaf node. The composite pattern will enable us to deal with all this uniformly.

Take a look at the conceptual diagram.

Conceptual diagram of composite design pattern

Enough talk!!

Let’s begin by adding a component class. The class is abstract in nature because it is dependent on actual objects to fulfill its dreams. We need one abstract method to get the size of a file or a directory.

Listing 1: a component class

Next!

We need to take care of the leaf node. In our example, Files are leaf nodes. So create a class for file nodes which will implement the abstract class that we created in listing 1.

Listing 2: class FileItem

Moving on,

Another component that we have is a directory. Let’s follow the same rules i.e. implement the abstract class that we created in listing 1.

Listings 3: class Directory

Finally,

our client class also known as caller class, which will make use of this pattern.

Listing 4: class Program

Now run your program and check the output…

The output

It works perfectly.

Everything works so well, Even Michael is celebrating.

Except one thing!!

the caller class is pretty messed up

We are adding up files without a proper order, plus every time we have to initialize a directory or file, we have to use a new keyword, which looks pretty messy.

What we can do is we can add a builder class in the middle. Here’s how you can design a builder pattern. You can learn Builder Design pattern in detail here.

Listing 5: class FileSystemBuilder

Also, notice that in our method SetCurrentDirectory(). We are not performing a recursive to search a directory, as it is not an optimal solution if the directory is large enough. Rather, we have used an iterative stack-based solution.

Don’t know what stack is? No worries I got you covered, Read this article.

Now see how our calling class looks:

Listing 6: class Program

We will display the object in JSON format to see it’s tree-like structure.

Now when you run this app, you’ll get the following output:

The final output

Now that’s how you roll.

Understand conceptually first, then it will be easy to implement.

I sincerely hope you enjoyed this article and that you’re inspired to apply what you’ve learned to your own applications. Thank you.

--

--