1. What is the composite pattern
The Composite Pattern is a commonly used object structural design pattern. It combines objects into a tree structure to represent a hierarchical "part-whole" relationship, allowing clients to handle individual objects and object compositions in a consistent manner.
2. Characteristics and advantages of the composite pattern
The main advantages of the composite pattern are:
- It can clearly define the hierarchical complex objects, representing all or part of the object hierarchy, making it easier to add new components.
- It provides a unified interface, making the access to composite parts and individual objects consistent, enabling clients to use single objects and composite objects uniformly.
3. Application scenarios of the composite pattern
- When you want to represent the part-whole hierarchy of objects.
- When you want clients to ignore the differences between composite objects and individual objects, and uniformly use all objects in the composite structure.
4. Implementation of the composite pattern in Golang
Suppose we are designing an e-commerce application, the product catalog is a good example of the composite pattern. A category can contain other categories, and also products (such as the electronics category contains phones, computers, and phones contain iPhones, Samsung phones, etc.).
4.1 UML Class Diagram
4.2 Example Introduction
In this example, we have Component
(obviously using the interface feature of object orientation) as the abstract base class, and Composite
and Leaf
both implement this interface, representing container objects and basic objects, respectively.
4.3 Implementation Step 1: Define the abstract component class
This method is usually defined in the interface class and is a key central operation.
4.3.1 Define the interface of the abstract component class
//Component: Basic component interface, defines the commonality of groups and individuals
type Component interface {
Search(string)
}
4.3.2 Implement basic methods of the abstract component class
This step is specifically implemented in the container component class and the leaf component class.
4.4 Implementation Step 2: Define the leaf component class
This concrete class represents the bottom category or object in the hierarchy, and it does not have the next layer of objects.
4.4.1 Inherit from the abstract component class
In Go, interface inheritance is implemented by the way methods are implemented through Struct.
4.4.2 Implement methods specific to the leaf component class
//Product: Represents a leaf node, i.e., a product, and cannot have child nodes
type Product struct {
Name string
}
//Search: Search for products
func (p *Product) Search(keyword string) {
if strings.Contains(p.Name, keyword) {
fmt.Printf("Product: '%s' contains keyword: '%s'\n", p.Name, keyword)
}
}
4.5 Implementation Step 3: Define the container component class
This class is used to store and manage child objects, generally including some methods for managing and organizing child objects, such as add(Component)
, remove(Component)
, etc.
4.5.1 Inherit from the abstract component class
This is also implemented by using Struct to implement the interface methods in Go.
4.5.2 Implementing Methods Specific to Container Component Class
// Category: Represents a container node, i.e., product category, which can have child nodes
type Category struct {
Name string
Children []Component
}
// Add: Add a child node
func (c *Category) Add(child Component) {
c.Children = append(c.Children, child)
}
// Remove: Remove a child node
func (c *Category) Remove(child Component) {
// Specific implementation omitted
}
// Search: Search for products
func (c *Category) Search(keyword string) {
fmt.Printf("Category: %s\n", c.Name)
for _, composite := range c.Children {
composite.Search(keyword)
}
}
4.6 Implementation Step 4: Client Code Example
Instantiate a structure, assemble it into a tree structure, and then call the access operation of the tree structure.
func main() {
root := &Category{Name: "Root"}
electronics := &Category{Name: "Electronics"}
phone := &Product{Name: "Phone"}
tv := &Product{Name: "Television"}
root.Add(electronics)
electronics.Add(phone)
electronics.Add(tv)
root.Search("phone") // This will search in all children
}