1. O que é o padrão composto

O Padrão Composto é um padrão de design estrutural de objetos comumente utilizado. Ele combina objetos em uma estrutura de árvore para representar um relacionamento hierárquico "parte-todo", permitindo que clientes manipulem objetos individuais e composições de objetos de maneira consistente.

2. Características e vantagens do padrão composto

As principais vantagens do padrão composto são:

  1. Ele pode claramente definir objetos complexos hierárquicos, representando toda ou parte da hierarquia de objetos, facilitando a adição de novos componentes.
  2. Ele fornece uma interface unificada, tornando o acesso às partes compostas e aos objetos individuais consistentes, permitindo que os clientes usem objetos individuais e objetos compostos de forma uniforme.

3. Cenários de aplicação do padrão composto

  1. Quando se deseja representar a hierarquia "parte-todo" de objetos.
  2. Quando se deseja que os clientes ignorem as diferenças entre objetos compostos e objetos individuais, e usem todos os objetos na estrutura composta de forma uniforme.

4. Implementação do padrão composto em Golang

Suponha que estejamos projetando um aplicativo de comércio eletrônico. O catálogo de produtos é um bom exemplo do padrão composto. Uma categoria pode conter outras categorias e também produtos (como a categoria de eletrônicos contém telefones, computadores, e os telefones contêm iPhones, Samsung, etc.).

4.1 Diagrama de Classe UML

Padrão Composto em Golang

4.2 Introdução do Exemplo

Neste exemplo, temos Component (obviamente usando o recurso de interface da orientação a objetos) como a classe base abstrata, e Composite e Leaf implementam essa interface, representando objetos contêiner e objetos básicos, respectivamente.

4.3 Etapa de Implementação 1: Definir a classe do componente abstrato

4.3.1 Definir a interface da classe de componente abstrato

// Componente: Interface do componente básico, define a generalidade dos grupos e indivíduos
type Component interface {
    Search(string)
}

4.3.2 Implementar métodos básicos da classe de componente abstrato

Esta etapa é implementada especificamente na classe de componente contêiner e na classe de componente folha.

4.4 Etapa de Implementação 2: Definir a classe de componente folha

Esta classe concreta representa a categoria inferior ou objeto na hierarquia, e não possui a próxima camada de objetos.

4.4.1 Herdar da classe de componente abstrato

Em Go, a herança de interface é implementada pela forma como os métodos são implementados por meio de Struct.

4.4.2 Implementar métodos específicos da classe de componente folha

// Produto: Representa um nó folha, ou seja, um produto, e não pode ter nós filhos
type Produto struct {
    Nome string
}

// Procurar: Procurar por produtos
func (p *Produto) Search(palavraChave string) {
    if strings.Contains(p.Nome, palavraChave) {
        fmt.Printf("Produto: '%s' contém a palavra-chave: '%s'\n", p.Nome, palavraChave)
    }
}

4.5 Etapa de Implementação 3: Definir a classe de componente contêiner

Esta classe é usada para armazenar e gerenciar objetos filhos, geralmente incluindo alguns métodos para gerenciar e organizar os objetos filhos, como adicionar(Componente), remover(Componente), etc.

4.5.1 Herdar da classe de componente abstrato

Isso também é implementado usando Struct para implementar os métodos de interface em Go.

4.5.2 Implementar métodos específicos da classe de componente contêiner

// Categoria: Representa um nó contêiner, ou seja, categoria de produto, que pode ter nós filhos
type Categoria struct {
    Nome     string
    Filhos []Component
}

// Adicionar: Adicionar um nó filho
func (c *Categoria) Adicionar(filho Component) {
    c.Filhos = append(c.Filhos, filho)
}

// Remove: Remover um nó filho
func (c *Categoria) Remover(filho Component) {
    // Implementação específica omitida
}

// Procurar: Procurar por produtos
func (c *Categoria) Procurar(palavraChave string) {
    fmt.Printf("Categoria: %s\n", c.Nome)
    for _, composto := range c.Filhos {
        composto.Procurar(palavraChave)
    }
}

4.6 Etapa de Implementação 4: Exemplo de Código do Cliente

Instancie uma estrutura, monte-a em uma estrutura de árvore e em seguida chame a operação de acesso da estrutura de árvore.

func main() {
    raiz := &Categoria{Nome: "Raiz"}
    eletronicos := &Categoria{Nome: "Eletrônicos"}

    telefone := &Produto{Nome: "Telefone"}
    tv := &Produto{Nome: "Televisão"}

    raiz.Adicionar(eletronicos)
    eletronicos.Adicionar(telefone)
    eletronicos.Adicionar(tv)

    raiz.Buscar("telefone") // Isso irá buscar em todos os filhos
}