Categories: Design Pattern

Structural Patterns – Composite

Composite – Lets the compose objects into the tree structures, and then according to the tree structures to composite them, which uses the part description and the overall layer to descript.

From Design Pattern – Creational Patterns

Structure

Composite pattern – Class diagram UML

Applicability

The developers want the client-side code to unify to use the simple objects and the complex objects to composite to build the new object such as a tree-like object structure.

Pros and Cons

PROS

  • Can work with the complex tree structures more conveniently.
  • The open-closed principle means the developer can create new elements into the project without breaking the existing code.

CONS

  • It will be challenging to provide a familiar interface for the classes whose functionality differs too much. Maybe the developers need to overgeneralize the component interface, which makes it harder to comprehend.

How to Implement

#1 Basic Sample

class Program
{
 static void Main(string[] args)
 {
  Client client = new Client();

  Leaf leaf = new Leaf();
  Console.WriteLine("Client: I get a simple component:");
  client.ClientCode(leaf);

  Composite tree = new Composite();
  Composite branch1 = new Composite();
  branch1.Add(new Leaf());
  branch1.Add(new Leaf());

  Composite branch2 = new Composite();
  branch2.Add(new Leaf());
  tree.Add(branch1);
  tree.Add(branch2);
  
  Console.WriteLine("Client: Now I've got a composite tree:");
  client.ClientCode(tree);

  Console.Write("Client: I don't need to check the components classes even when managing the tree:\n");
  client.ClientCode2(tree, leaf);

  Console.ReadKey();
 }
}

abstract class Component
{
 public Component() { }

 public abstract string Operation();

 public virtual void Add(Component component)
 {
  throw new NotImplementedException();
 }

 public virtual void Remove(Component component)
 {
  throw new NotImplementedException();
 }

 public virtual bool IsComposite() => true;
}

class Leaf : Component
{
 public override string Operation() =>"Object";

 public override bool IsComposite() => false;
}

class Composite : Component
{
 protected List<Component> _children = new List<Component>();

 public override void Add(Component component)
 {
  this._children.Add(component);
 }

 public override void Remove(Component component)
 {
  this._children.Remove(component);
 }

 public override string Operation()
 {
  int i = 0;
  string result = "Branch(";

  foreach (Component component in this._children)
  {
   result += component.Operation();
   if (i != this._children.Count - 1)
   {
    result += "+";
   }
   i++;
  }

  return result + ")";
 }
}

class Client
{
 public void ClientCode(Component leaf)
 {
  Console.WriteLine($"RESULT: {leaf.Operation()}\n");
 }

 public void ClientCode2(Component component1, Component component2)
 {
  if (component1.IsComposite())
  {
   component1.Add(component2);
  }

  Console.WriteLine($"RESULT: {component1.Operation()}");
 }
}

Note: This sample is from Refactoring.Guru website because I think it is straightforward to understand the composite pattern concepts for the beginner. I consider more other websites and my source code projects. However, I still think the program logic is too circuitous and doesn’t easily understand the composite concepts. If you have new ideas about the composite pattern sample, please, tell me your idea and your logic.

#2 Web Application Project

Step 1 Create the generic type mechanism for the composite pattern in the Core project and the Infra project.

Fig 1 Generic type mechanism – Solution explorer

Step 2 Create the composite class file, the component class file and the CompositeElement class file under the Core project.

The component class file code shows below:

public abstract class Component
{
 public Component() { }

 public abstract object Operation(int? id);

 public virtual void Add(object obj) => throw new NotImplementedException();

 public virtual void Remove(object obj) => throw new NotImplementedException();

 public virtual bool IsComposite() => true;
}
Fig 2 Component.cs source code

The composite class file code shows below:

public class Composite : Component
{

 protected List<object> children = new List<object>();

 public override void Add(object obj)
 {
  this.children.Add(obj);
 }

 public override void Remove(object obj)
 {
  this.children.Remove(obj);
 }

 public override object Operation(int? id) 
 {
  List<object> Result = new List<object>();

  foreach (object objItem in this.children)
  {
   Result.Add(objItem);
  }

  return Result;
 }
}
Fig 3 Composite.cs file source code

The CompositeElement class file code shows below:

public class CompositeElement<T> : Composite where T : class
{
 private readonly IComposite<T> repo;

 public CompositeElement(IComposite<T> _repo) {
  this.repo = _repo;
 }

 public override object Operation(int? id)
 {
  return this.repo.GetById(id).Result;
 }

 public override bool IsComposite() => false;
}
Fig 4 CompositeElement.cs file source code

Step 3. Create the Controller files with the views part in the Web projects. The Controller file name sets “CompositeController.cs.” Add the related-composite file to the web project’s startup.cs file.

Fig 5 Startup.cs file about the composite pattern
Fig 6 Composite pattern result

Reference

davidsky69

View Comments

Recent Posts

API Gateway in .NET 5 with Ocelot

What is the API gateway? An API gateway is an API management tool that sits…

3 years ago

.NET 5 application with Onion architecture

The .NET 5 SDK is a kind of milestone in the .NET world. The .NET…

4 years ago

SOLID Principles – Dependency inversion principle

In object-oriented design, the dependency inversion principle is a specific methodology for loosely coupling software…

4 years ago

SOLID Principles – Interface segregation principle

In the field of software engineering, the interface segregation principle (ISP) states that no code…

4 years ago

SOLID Principles – Liskov substitution principle

Subtype Requirement: Let  be a property provable about objects  of type T. Then  should be true for objects  of type S where S is…

4 years ago

SOLID Principles – Open-closed principle

In object-oriented programming, the open–closed principle states "software entities (classes, modules, functions, etc.) should be…

4 years ago