本文目录导读:

我来详细讲解PHP中的组合模式处理树形结构。
什么是组合模式
组合模式是一种结构型设计模式,它允许将对象组合成树形结构来表示"部分-整体"的层次关系,客户端可以统一地处理单个对象和组合对象。
核心组件
- Component(组件):抽象接口,定义通用方法
- Leaf(叶子节点):没有子节点的对象
- Composite(组合节点):有子节点的对象,实现子节点管理
完整实现示例
基础组合模式
<?php
// 组件接口
interface Component
{
public function getName(): string;
public function getSize(): int;
public function display(int $indent = 0): string;
public function add(Component $component): void;
public function remove(Component $component): void;
public function getChild(int $index): ?Component;
}
// 叶子节点(文件)
class File implements Component
{
private string $name;
private int $size;
public function __construct(string $name, int $size)
{
$this->name = $name;
$this->size = $size;
}
public function getName(): string
{
return $this->name;
}
public function getSize(): int
{
return $this->size;
}
public function display(int $indent = 0): string
{
return str_repeat(" ", $indent) . "📄 {$this->name} ({$this->size} bytes)\n";
}
// 叶子节点没有子节点,这些方法可以空实现或抛异常
public function add(Component $component): void
{
throw new Exception("Cannot add to a file");
}
public function remove(Component $component): void
{
throw new Exception("Cannot remove from a file");
}
public function getChild(int $index): ?Component
{
return null;
}
}
// 组合节点(文件夹)
class Directory implements Component
{
private string $name;
private array $children = [];
public function __construct(string $name)
{
$this->name = $name;
}
public function getName(): string
{
return $this->name;
}
public function getSize(): int
{
$totalSize = 0;
foreach ($this->children as $child) {
$totalSize += $child->getSize();
}
return $totalSize;
}
public function display(int $indent = 0): string
{
$output = str_repeat(" ", $indent) . "📁 {$this->name}/\n";
foreach ($this->children as $child) {
$output .= $child->display($indent + 1);
}
return $output;
}
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 getChild(int $index): ?Component
{
return $this->children[$index] ?? null;
}
public function getChildren(): array
{
return $this->children;
}
}
// 使用示例
function testFileSystem()
{
$root = new Directory("root");
$images = new Directory("images");
$images->add(new File("logo.png", 5000));
$images->add(new File("banner.jpg", 10000));
$docs = new Directory("docs");
$docs->add(new File("readme.txt", 2000));
$project = new Directory("project");
$project->add($images);
$project->add($docs);
$project->add(new File("main.php", 8000));
$root->add($project);
echo "文件系统结构:\n";
echo $root->display();
echo "\n总大小: " . $root->getSize() . " bytes\n";
}
testFileSystem();
增强版:组织架构示例
<?php
// 员工接口
interface EmployeeInterface
{
public function getName(): string;
public function getPosition(): string;
public function getSalary(): float;
public function getSubordinatesCount(): int;
public function display(int $indent = 0): string;
public function add(EmployeeInterface $employee): void;
public function remove(EmployeeInterface $employee): void;
public function getTotalSalary(): float;
}
// 员工(叶子节点)
class Employee implements EmployeeInterface
{
private string $name;
private string $position;
private float $salary;
public function __construct(string $name, string $position, float $salary)
{
$this->name = $name;
$this->position = $position;
$this->salary = $salary;
}
public function getName(): string
{
return $this->name;
}
public function getPosition(): string
{
return $this->position;
}
public function getSalary(): float
{
return $this->salary;
}
public function getSubordinatesCount(): int
{
return 0;
}
public function display(int $indent = 0): string
{
return str_repeat(" ", $indent) . "👤 {$this->name} - {$this->position} (¥{$this->salary})\n";
}
public function add(EmployeeInterface $employee): void
{
throw new Exception("Cannot add subordinates to an employee");
}
public function remove(EmployeeInterface $employee): void
{
throw new Exception("Cannot remove subordinates from an employee");
}
public function getTotalSalary(): float
{
return $this->salary;
}
}
// 部门经理(组合节点)
class Manager implements EmployeeInterface
{
private string $name;
private string $position;
private float $salary;
private array $subordinates = [];
public function __construct(string $name, string $position, float $salary)
{
$this->name = $name;
$this->position = $position;
$this->salary = $salary;
}
public function getName(): string
{
return $this->name;
}
public function getPosition(): string
{
return $this->position;
}
public function getSalary(): float
{
return $this->salary;
}
public function getSubordinatesCount(): int
{
$count = count($this->subordinates);
foreach ($this->subordinates as $subordinate) {
$count += $subordinate->getSubordinatesCount();
}
return $count;
}
public function display(int $indent = 0): string
{
$output = str_repeat(" ", $indent) . "👔 {$this->name} - {$this->position} (¥{$this->salary})\n";
foreach ($this->subordinates as $subordinate) {
$output .= $subordinate->display($indent + 1);
}
return $output;
}
public function add(EmployeeInterface $employee): void
{
$this->subordinates[] = $employee;
}
public function remove(EmployeeInterface $employee): void
{
$this->subordinates = array_filter($this->subordinates, function ($sub) use ($employee) {
return $sub !== $employee;
});
}
public function getTotalSalary(): float
{
$total = $this->salary;
foreach ($this->subordinates as $subordinate) {
$total += $subordinate->getTotalSalary();
}
return $total;
}
}
// 使用示例
function testOrganizationStructure()
{
// 创建组织结构
$ceo = new Manager("张三", "CEO", 50000);
$cto = new Manager("李四", "CTO", 35000);
$cfo = new Manager("王五", "CFO", 30000);
// 技术团队
$devLead1 = new Manager("赵六", "开发组长", 25000);
$devLead2 = new Manager("钱七", "开发组长", 25000);
$cto->add($devLead1);
$cto->add($devLead2);
$devLead1->add(new Employee("孙八", "高级开发", 20000));
$devLead1->add(new Employee("周九", "中级开发", 15000));
$devLead2->add(new Employee("吴十", "测试工程师", 18000));
$devLead2->add(new Employee("郑十一", "运维工程师", 22000));
// 财务团队
$cfo->add(new Employee("冯十二", "会计", 12000));
$cfo->add(new Employee("陈十三", "出纳", 8000));
$ceo->add($cto);
$ceo->add($cfo);
// 展示组织结构
echo "公司组织结构:\n";
echo $ceo->display();
echo "\n公司总人力成本: ¥" . $ceo->getTotalSalary() . "\n";
echo "公司总人数: " . $ceo->getSubordinatesCount() . "\n";
}
testOrganizationStructure();
高级功能:树形数据遍历
<?php
// 树形数据遍历迭代器
class TreeIterator implements Iterator
{
private array $nodes = [];
private int $position = 0;
public function __construct(Component $root)
{
$this->flatten($root);
}
private function flatten(Component $node): void
{
$this->nodes[] = $node;
// 如果是组合节点,遍历子节点
if ($node instanceof Directory) {
foreach ($node->getChildren() as $child) {
$this->flatten($child);
}
}
}
public function current(): Component
{
return $this->nodes[$this->position];
}
public function key(): int
{
return $this->position;
}
public function next(): void
{
$this->position++;
}
public function rewind(): void
{
$this->position = 0;
}
public function valid(): bool
{
return isset($this->nodes[$this->position]);
}
public function count(): int
{
return count($this->nodes);
}
}
// 访问者模式示例(可选增强)
interface Visitor
{
public function visitFile(File $file): void;
public function visitDirectory(Directory $directory): void;
}
class FileSizeVisitor implements Visitor
{
private int $totalSize = 0;
private int $fileCount = 0;
private int $dirCount = 0;
public function visitFile(File $file): void
{
$this->totalSize += $file->getSize();
$this->fileCount++;
}
public function visitDirectory(Directory $directory): void
{
$this->dirCount++;
foreach ($directory->getChildren() as $child) {
if ($child instanceof File) {
$this->visitFile($child);
} elseif ($child instanceof Directory) {
$this->visitDirectory($child);
}
}
}
public function getStats(): array
{
return [
'totalSize' => $this->totalSize,
'fileCount' => $this->fileCount,
'dirCount' => $this->dirCount
];
}
}
// 高级使用示例
function testAdvancedFeatures()
{
// 构建文件系统
$root = new Directory("root");
$src = new Directory("src");
$src->add(new File("app.php", 15000));
$src->add(new File("config.php", 3000));
$public = new Directory("public");
$public->add(new File("index.html", 5000));
$public->add(new File("style.css", 2000));
$root->add($src);
$root->add($public);
$root->add(new File("README.md", 1000));
// 使用迭代器遍历
echo "使用迭代器遍历所有节点:\n";
$iterator = new TreeIterator($root);
foreach ($iterator as $index => $node) {
echo " [{$index}] {$node->getName()}\n";
}
echo "总节点数: " . count($iterator) . "\n\n";
// 使用访问者统计
$visitor = new FileSizeVisitor();
$visitor->visitDirectory($root);
$stats = $visitor->getStats();
echo "文件系统统计:\n";
echo " 文件数量: {$stats['fileCount']}\n";
echo " 文件夹数量: {$stats['dirCount']}\n";
echo " 总大小: {$stats['totalSize']} bytes\n";
}
testAdvancedFeatures();
实际应用场景
菜单系统
class MenuItem extends Component
{
// 菜单项可以是叶子或组合
}
class Menu extends Composite
{
// 菜单包含子菜单和菜单项
}
权限树
class PermissionNode
{
// 权限模块可以有子权限
}
分类系统
class Category
{
// 商品分类支持无限层级
}
最佳实践
- 统一接口:叶子节点和组合节点实现相同接口
- 安全操作:叶子节点对添加/移除操作抛出异常或静默处理
- 递归操作:使用递归处理树形结构
- 缓存机制:对于频繁访问的操作可以考虑缓存结果
- 性能优化:大型树形结构考虑使用生成器或延迟加载
优缺点
优点:
- 清晰地表示部分-整体层级关系
- 客户端可以一致地处理简单和复杂元素
- 易于增加新类型的组件
缺点:
- 可能会使设计过于复杂
- 对类型系统的约束较弱
组合模式非常适合处理树形结构,如文件系统、组织架构、菜单系统等场景。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播