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:
- Ele pode claramente definir objetos complexos hierárquicos, representando toda ou parte da hierarquia de objetos, facilitando a adição de novos componentes.
- 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
- Quando se deseja representar a hierarquia "parte-todo" de objetos.
- 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
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
}