设计模式解密:组合模式的终极指南(PHP/Go双实现)
一、什么是组合模式?
组合模式(Composite Pattern) 是一种结构型设计模式,用于将对象组合成树形结构以表示“部分-整体”的层次关系。组合模式的核心思想是通过统一的接口处理单个对象和组合对象,使客户端可以一致地处理简单元素和复杂元素。
核心角色:
组件接口(Component):定义叶节点和组合节点的通用接口
叶节点(Leaf):表示树形结构中的叶子节点(无子节点)
组合节点(Composite):表示树形结构中的分支节点(有子节点)
二、适用场景
✅ 需要表示“部分-整体”的层次结构
✅ 需要统一处理简单元素和复杂元素
✅ 需要动态添加或删除子节点
✅ 需要递归遍历树形结构
三、PHP实现方案
1. 基础实现
interface Component {
public function operation(): string;
}
class Leaf implements Component {
private $name;
public function __construct(string $name) {
$this->name = $name;
}
public function operation(): string {
return "Leaf: " . $this->name;
}
}
class Composite implements Component {
private $children = [];
public function add(Component $component): void {
$this->children[] = $component;
}
public function remove(Component $component): void {
$this->children = array_filter($this->children, function ($child) use ($component) {
return $child !== $component;
});
}
public function operation(): string {
$results = [];
foreach ($this->children as $child) {
$results[] = $child->operation();
}
return "Composite: [" . implode(", ", $results) . "]";
}
}
// 使用示例
$leaf1 = new Leaf("Leaf 1");
$leaf2 = new Leaf("Leaf 2");
$leaf3 = new Leaf("Leaf 3");
$composite1 = new Composite();
$composite1->add($leaf1);
$composite1->add($leaf2);
$composite2 = new Composite();
$composite2->add($leaf3);
$composite2->add($composite1);
echo $composite2->operation(); // 输出:Composite: [Leaf: Leaf 3, Composite: [Leaf: Leaf 1, Leaf: Leaf 2]]
2. 进阶实现(带层级缩进)
interface Component {
public function operation(int $level = 0): string;
}
class Leaf implements Component {
private $name;
public function __construct(string $name) {
$this->name = $name;
}
public function operation(int $level = 0): string {
return str_repeat(" ", $level) . "Leaf: " . $this->name . "\n";
}
}
class Composite implements Component {
private $children = [];
public function add(Component $component): void {
$this->children[] = $component;
}
public function remove(Component $component): void {
$this->children = array_filter($this->children, function ($child) use ($component) {
return $child !== $component;
});
}
public function operation(int $level = 0): string {
$results = [str_repeat(" ", $level) . "Composite:\n"];
foreach ($this->children as $child) {
$results[] = $child->operation($level + 1);
}
return implode("", $results);
}
}
// 使用示例
$leaf1 = new Leaf("Leaf 1");
$leaf2 = new Leaf("Leaf 2");
$leaf3 = new Leaf("Leaf 3");
$composite1 = new Composite();
$composite1->add($leaf1);
$composite1->add($leaf2);
$composite2 = new Composite();
$composite2->add($leaf3);
$composite2->add($composite1);
echo $composite2->operation();
// 输出:
// Composite:
// Leaf: Leaf 3
// Composite:
// Leaf: Leaf 1
// Leaf: Leaf 2
四、Go实现方案
1. 基础实现
package main
import (
"fmt"
"strings"
)
type Component interface {
Operation() string
}
type Leaf struct {
name string
}
func NewLeaf(name string) *Leaf {
return &Leaf{name: name}
}
func (l *Leaf) Operation() string {
return "Leaf: " + l.name
}
type Composite struct {
children []Component
}
func NewComposite() *Composite {
return &Composite{children: []Component{}}
}
func (c *Composite) Add(component Component) {
c.children = append(c.children, component)
}
func (c *Composite) Remove(component Component) {
for i, child := range c.children {
if child == component {
c.children = append(c.children[:i], c.children[i+1:]...)
break
}
}
}
func (c *Composite) Operation() string {
results := []string{}
for _, child := range c.children {
results = append(results, child.Operation())
}
return "Composite: [" + strings.Join(results, ", ") + "]"
}
// 使用示例
func main() {
leaf1 := NewLeaf("Leaf 1")
leaf2 := NewLeaf("Leaf 2")
leaf3 := NewLeaf("Leaf 3")
composite1 := NewComposite()
composite1.Add(leaf1)
composite1.Add(leaf2)
composite2 := NewComposite()
composite2.Add(leaf3)
composite2.Add(composite1)
fmt.Println(composite2.Operation()) // 输出:Composite: [Leaf: Leaf 3, Composite: [Leaf: Leaf 1, Leaf: Leaf 2]]
}
2. 进阶实现(带层级缩进)
package main
import (
"fmt"
"strings"
)
type Component interface {
Operation(level int) string
}
type Leaf struct {
name string
}
func NewLeaf(name string) *Leaf {
return &Leaf{name: name}
}
func (l *Leaf) Operation(level int) string {
return strings.Repeat(" ", level) + "Leaf: " + l.name + "\n"
}
type Composite struct {
children []Component
}
func NewComposite() *Composite {
return &Composite{children: []Component{}}
}
func (c *Composite) Add(component Component) {
c.children = append(c.children, component)
}
func (c *Composite) Remove(component Component) {
for i, child := range c.children {
if child == component {
c.children = append(c.children[:i], c.children[i+1:]...)
break
}
}
}
func (c *Composite) Operation(level int) string {
results := []string{strings.Repeat(" ", level) + "Composite:\n"}
for _, child := range c.children {
results = append(results, child.Operation(level+1))
}
return strings.Join(results, "")
}
// 使用示例
func main() {
leaf1 := NewLeaf("Leaf 1")
leaf2 := NewLeaf("Leaf 2")
leaf3 := NewLeaf("Leaf 3")
composite1 := NewComposite()
composite1.Add(leaf1)
composite1.Add(leaf2)
composite2 := NewComposite()
composite2.Add(leaf3)
composite2.Add(composite1)
fmt.Println(composite2.Operation(0))
// 输出:
// Composite:
// Leaf: Leaf 3
// Composite:
// Leaf: Leaf 1
// Leaf: Leaf 2
}
五、关键实现差异对比
六、模式优缺点分析
👍 优点:
统一处理简单元素和复杂元素:客户端可以一致地处理单个对象和组合对象
简化客户端代码:客户端无需关心对象的具体类型
支持递归遍历:方便处理树形结构
👎 缺点:
增加复杂度:引入额外的类和接口
设计难度高:需要合理划分组件接口
七、实际应用案例
1. 文件系统
// PHP示例
$file1 = new File("file1.txt");
$file2 = new File("file2.txt");
$folder1 = new Folder("Folder 1");
$folder1->add($file1);
$folder1->add($file2);
$file3 = new File("file3.txt");
$folder2 = new Folder("Folder 2");
$folder2->add($file3);
$folder2->add($folder1);
echo $folder2->operation();
2. 组织架构
// Go示例
employee1 := NewEmployee("John Doe")
employee2 := NewEmployee("Jane Doe")
department1 := NewDepartment("Engineering")
department1.Add(employee1)
department1.Add(employee2)
employee3 := NewEmployee("Alice Smith")
department2 := NewDepartment("HR")
department2.Add(employee3)
department2.Add(department1)
fmt.Println(department2.Operation(0))
3. 菜单系统
// PHP示例
$item1 = new MenuItem("Home");
$item2 = new MenuItem("About");
$subMenu = new Menu("Services");
$subMenu->add(new MenuItem("Web Development"));
$subMenu->add(new MenuItem("Mobile Development"));
$menu = new Menu("Main Menu");
$menu->add($item1);
$menu->add($item2);
$menu->add($subMenu);
echo $menu->operation();
八、与装饰器模式的区别
九、总结
组合模式是处理树形结构的利器,通过统一的接口处理单个对象和组合对象,它提供了极大的灵活性和扩展性。无论是PHP的数组存储还是Go的切片存储,组合模式都能显著提升代码的可维护性和可扩展性。
在下一篇文章中,我们将探讨 装饰器模式 及其在动态扩展对象功能中的应用。敬请期待!
下一篇预告:设计模式系列(九)——装饰器模式:动态扩展的艺术
License:
CC BY 4.0