Composite pattern

De Banane Atomic
Aller à la navigationAller à la recherche

Description

  • Compose objects into tree structures to represent part-whole hierarchies.
    Composite lets clients treat individual objects and compositions of objects uniformly
  • Arrange structured hierarchies so that single components and groups of components can be treated in the same way

Exemple

IComponent.cs
public interface IComponent
{
    string Name { get; set; }
    void Add(IComponent component);
    void Remove(IComponent component);
    string Display(int depth);
    IComponent Find(string name);
    void AddSuffix(string suffix);
}
User.cs
public class User : IComponent
{
    public string Name { get; set; }

    public User(string name)
    {
        this.Name = name;
    }

    public void Add(IComponent component)
    {
        throw new NotSupportedException("Cannot add a component to a user.");
    }

    public void Remove(IComponent component)
    {
    }

    public string Display(int depth) => $"{new String('-', depth)} {Name}\n";

    public IComponent Find(string name) => name.Equals(this.Name) ? this : null;

    public void AddSuffix(string suffix)
    {
        Name += suffix;
    }
}
UsersGroup.cs
public class UsersGroup : IComponent
{
    public string Name { get; set; }
    ICollection<IComponent> components;

    public UsersGroup(string name)
    {
        this.components = new List<IComponent>();
        this.Name = name;
    }

    public void Add(IComponent component)
    {
        components.Add(component);
    }

    public void Remove(IComponent componentToRemove)
    {
        if (!components.Remove(componentToRemove))
        {
            foreach (var component in components)
            {
                component.Remove(componentToRemove);
            }
        }
    }

    public string Display(int depth)
    {
        var stringBuilder = new StringBuilder();
        stringBuilder.AppendLine($"{new String('-', depth)} {Name}");

        foreach (var component in components)
        {
            stringBuilder.Append(component.Display(depth + 1));
        }

        return stringBuilder.ToString();
    }

    public IComponent Find(string name)
    {
        if (name.Equals(this.Name))
            return this;

        foreach (var component in components)
        {
            var matchingComponent = component.Find(name);
            if (matchingComponent != null)
                return matchingComponent;
        }

        return null;
    }

    public void AddSuffix(string suffix)
    {
        Name += suffix;
        foreach (var component in components)
        {
            component.AddSuffix(suffix);
        }
    }
}
Cs.svg
var group1 = new UsersGroup("Group1");
var user1 = new User("Nicolas");
group1.Add(user1);
var user2 = new User("Guillaume");
group1.Add(user2);

var group2 = new UsersGroup("Group2");
var user3 = new User("Paul");
group2.Add(user3);
var user4 = new User("Marie");
group2.Add(user4);

var group = new UsersGroup("Group");
group.Add(group1);
group.Add(group2);
var user5 = new User("Jean");
group.Add(user5);

group.AddSuffix("!");

group.Remove(group.Find("Guillaume"));
group.Remove(group.Find("Group2"));

Console.WriteLine(group.Display(1));