Padrão Composto C#

Resumo : neste tutorial, você aprenderá como usar o padrão C# Composite para tratar objetos individuais e composições de objetos de maneira uniforme.

Introdução ao padrão composto C#

O padrão C# Composite é um padrão de design estrutural que permite criar uma hierarquia de objetos individuais e coleções de objetos por meio de uma interface compartilhada . Isso permite que o cliente trate objetos individuais e o grupo de objetos de maneira uniforme.

Como um objeto individual e uma coleção de objetos compartilham uma interface comum , o cliente não precisa saber onde está gerenciando um único objeto ou um objeto de coleção.

Em vez disso, o cliente pode fazer uso do polimorfismo sem ter que aplicar instruções de condição desnecessárias que verificam se o objeto é um objeto individual ou uma coleção de objetos.

Para ilustrar esse padrão composto, imagine que você precisa gerenciar uma lista de materiais (BOM) que contém uma lista de materiais para fazer uma parte de um produto (montagem) ou o produto inteiro.

Em alguns casos, é necessário executar a mesma operação em um componente, seja ele um componente único ou uma montagem que consiste em componentes individuais.

Por exemplo, você deve conseguir obter o custo de um componente sem saber se é um componente ou uma montagem.

O diagrama UML a seguir ilustra o padrão composto:

Padrão composto C#

Neste diagrama:

  • IComponent: esta é uma interface compartilhada que especifica a operação que cada componente precisa implementar.
  • Leaf: Este é um componente individual.
  • Composite: Esta é uma coleção de componentes. Pode incluir folhas e outros compostos.
  • Client: Esta classe tem acesso a diferentes componentes através da interface compartilhada IComponent, aproveitando o polimorfismo.

Exemplo de padrão composto C#

O seguinte programa C# demonstra o padrão composto:

// Shared interface
public interface IComponent
{
    string Name { get; set; }
    int Quantity { get; set; }
    double GetCost();
}

// Leaf component
public class Part : IComponent
{
    public string Name { get; set; }
    public int Quantity { get; set; }
    public double Cost { get; set; }
    public Part(string name, int quantity, double cost)
    {
        Name = name;
        Quantity = quantity;
        Cost = cost;
    }

    public double GetCost() => Cost * Quantity;
}

// Composite component
public class Assembly : IComponent
{
    public string Name {  get; set; }
    public int Quantity { get; set; }

    private readonly List<IComponent> _components = new();

    public Assembly(string name, int quantity, IEnumerable<IComponent> components)
    {
        Name = name;
        Quantity = quantity;
        _components.AddRange(components);
    }

    public double GetCost() => _components.Sum(component => component.GetCost());
}

// Client
public class Program
{
    public static void Main(string[] args)
    {

        // parts
        var engine = new Part("Engine", 1, 5000.0);
        var tires = new Part("Tires", 4, 1000.0);

        // assembly
        var body = new Assembly(
            "Body", 
            1, 
            new List<IComponent> {
                new Part("Frame", 1, 2000.0),
                new Part("Doors", 4, 1000.0),
                new Part("Windows", 6, 500.0)
            }
        );


        // car
        var car = new Assembly(
            "Car", 
            1, 
            new List<IComponent> {
                engine,
                tires,
                body
        });

        // Calculate the cost of the car
        var carCost = car.GetCost();

        Console.WriteLine($"The cost of the car is: {carCost:C}");
    }
}
Linguagem de código:  C#  ( cs )

Saída:

The cost of the car is: $18,000.00Linguagem de código:  C#  ( cs )

Como funciona.

Primeiro, defina uma interface compartilhada IComponentque tanto o componente quanto o assembly precisam implementar. A IComponentinterface possui as propriedades Namee Quantity, bem como o GetCost()método:

public interface IComponent
{
    string Name { get; set; }
    int Quantity { get; set;}

    double GetCost();
}Linguagem de código:  C#  ( cs )

Segundo, defina a Partclasse que serve como folha. A Partclasse implementa a IComponentinterface:

public class Part : IComponent
{
    public string Name { get; set; }
    public int Quantity {  get; set; }
    public double Cost { get; set; }

    public Part(string name, int quantity, double cost)
    {
        Name = name;
        Quantity = quantity;
        Cost = cost;
    }

    public double GetCost() => Cost * Quantity;
}Linguagem de código:  C#  ( cs )

Na classe Peça, GetCost()calcula o custo multiplicando o custo de cada componente pela quantidade.

Terceiro, defina a Assemblyclasse que serve como composta. A Assemblyclasse implementa a IComponentinterface e possui um campo do tipo IEnumerable< IComponent> que representa uma lista de IComponent:

public class Assembly : IComponent
{
    public string Name {  get; set; }
    public int Quantity { get; set; }

    private readonly List<IComponent> _components = new();

    public Assembly(string name, int quantity, IEnumerable<IComponent> components)
    {
        Name = name;
        Quantity = quantity;
        _components.AddRange(components);
    }

    public double GetCost() => _components.Sum(component => component.GetCost());
}Linguagem de código:  C#  ( cs )

O GetCost()método calcula o custo total usando o Summétodo de extensão somando os custos de todos os componentes da _componentlista.

Por fim, defina a Programclasse que usa as classes Parte Assemblypara construir um produto Carro e chame o GetCost()objeto carro para obter o custo total do carro:

public class Program
{
    public static void Main(string[] args)
    {

        // parts
        var engine = new Part("Engine", 1, 5000.0);
        var tires = new Part("Tires", 4, 1000.0);

        // assembly
        var body = new Assembly("Body", 1, new List<IComponent> {
            new Part("Frame", 1, 2000.0),
            new Part("Doors", 4, 1000.0),
            new Part("Windows", 6, 500.0)
        });

        // car
        var car = new Assembly("Car", 1, new List<IComponent>{
            engine,
            tires,
            body
        });

        // Calculate the cost of the car
        var carCost = car.GetCost();

        Console.WriteLine($"The cost of the car is: {carCost:C}");
    }
}Linguagem de código:  C#  ( cs )

Resumo

  • Use o padrão Composite para tratar objetos individuais e composições de objetos de maneira uniforme.

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *