当前位置: 首页 > news >正文

完整教程:【设计模式手册010】组合模式 - 树形结构的优雅处理

完整教程:【设计模式手册010】组合模式 - 树形结构的优雅处理

设计模式手册010:组合模式 - 树形结构的优雅处理

本文是「设计模式手册」系列第010篇,我们将深入探讨组合模式,这种模式用树形结构来表示"部分-整体"的层次结构,让客户端可以统一地处理单个对象和对象组合。

1. 场景:我们为何需要组合模式?

在软件开发中,我们经常遇到需要处理树形结构数据的场景:

传统做法的困境

// 不同的类需要不同的处理方式
public class File {
private String name;
private long size;
public File(String name, long size) {
this.name = name;
this.size = size;
}
public String getName() { return name; }
public long getSize() { return size; }
public void display() {
System.out.println("文件: " + name + " (" + size + " bytes)");
}
}
public class Directory {
private String name;
private List<Object> children; // 混合类型!public Directory(String name) {this.name = name;this.children = new ArrayList<>();}public void add(Object child) {children.add(child);}public void display() {System.out.println("目录: " + name);for (Object child : children) {if (child instanceof File) {((File) child).display();} else if (child instanceof Directory) {((Directory) child).display();}}}public long getSize() {long totalSize = 0;for (Object child : children) {if (child instanceof File) {totalSize += ((File) child).getSize();} else if (child instanceof Directory) {totalSize += ((Directory) child).getSize();}}return totalSize;}}// 问题:客户端需要区分不同类型public class FileSystemClient {public static void main(String[] args) {Directory root = new Directory("root");File file1 = new File("readme.txt", 1024);Directory subDir = new Directory("documents");File file2 = new File("report.doc", 2048);root.add(file1);root.add(subDir);subDir.add(file2);// 显示时需要类型判断root.display();// 计算大小需要类型判断System.out.println("总大小: " + root.getSize());}}

这种实现的痛点

  • 类型判断:需要不断检查对象类型
  • 代码重复:相同的遍历逻辑在不同方法中重复
  • 违反开闭原则:新增类型需要修改所有处理代码
  • 客户端复杂:客户端需要了解具体类型

2. 组合模式:定义与本质

2.1 模式定义

组合模式(Composite Pattern):将对象组合成树形结构以表示"部分-整体"的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

2.2 核心角色

// 组件接口:定义叶子和容器的共同接口
public interface FileSystemComponent {
String getName();
long getSize();
void display();
void add(FileSystemComponent component);
void remove(FileSystemComponent component);
FileSystemComponent getChild(int index);
}
// 叶子组件:表示叶子节点,没有子节点
public class File implements FileSystemComponent {
private String name;
private long size;
public File(String name, long size) {
this.name = name;
this.size = size;
}
@Override
public String getName() {
return name;
}
@Override
public long getSize() {
return size;
}
@Override
public void display() {
System.out.println("文件: " + name + " (" + size + " bytes)");
}
// 叶子节点不支持这些操作,可以抛出异常或忽略
@Override
public void add(FileSystemComponent component) {
throw new UnsupportedOperationException("文件不支持添加子组件");
}
@Override
public void remove(FileSystemComponent component) {
throw new UnsupportedOperationException("文件不支持删除子组件");
}
@Override
public FileSystemComponent getChild(int index) {
throw new UnsupportedOperationException("文件没有子组件");
}
}
// 容器组件:表示容器节点,可以包含子节点
public class Directory implements FileSystemComponent {
private String name;
private List<FileSystemComponent> children;public Directory(String name) {this.name = name;this.children = new ArrayList<>();}@Overridepublic String getName() {return name;}@Overridepublic long getSize() {long totalSize = 0;for (FileSystemComponent child : children) {totalSize += child.getSize();}return totalSize;}@Overridepublic void display() {System.out.println("目录: " + name);for (FileSystemComponent child : children) {child.display(); // 递归调用}}@Overridepublic void add(FileSystemComponent component) {children.add(component);}@Overridepublic void remove(FileSystemComponent component) {children.remove(component);}@Overridepublic FileSystemComponent getChild(int index) {if (index >= 0 && index < children.size()) {return children.get(index);}return null;}// 容器特有的方法public int getChildCount() {return children.size();}public List<FileSystemComponent> getChildren() {return new ArrayList<>(children);}}

3. 深入理解:组合模式的多维视角

3.1 第一重:透明式 vs 安全式

透明式组合模式
// 透明式:在组件接口中声明所有方法,包括管理子组件的方法
public interface Component {
void operation();
void add(Component component);
void remove(Component component);
Component getChild(int index);
}
// 叶子节点需要实现所有方法,包括不支持的方法
public class Leaf implements Component {
@Override
public void operation() {
System.out.println("叶子操作");
}
@Override
public void add(Component component) {
throw new UnsupportedOperationException();
}
@Override
public void remove(Component component) {
throw new UnsupportedOperationException();
}
@Override
public Component getChild(int index) {
throw new UnsupportedOperationException();
}
}
安全式组合模式
// 安全式:在组件接口中只声明公共方法,管理子组件的方法在容器接口中声明
public interface Component {
void operation();
}
public interface Composite extends Component {
void add(Component component);
void remove(Component component);
Component getChild(int index);
}
// 叶子节点只需要实现操作方法
public class Leaf implements Component {
@Override
public void operation() {
System.out.println("叶子操作");
}
}
// 容器节点实现复合接口
public class ConcreteComposite implements Composite {
private List<Component> children = new ArrayList<>();@Overridepublic void operation() {System.out.println("容器操作");for (Component child : children) {child.operation();}}@Overridepublic void add(Component component) {children.add(component);}@Overridepublic void remove(Component component) {children.remove(component);}@Overridepublic Component getChild(int index) {return children.get(index);}}

3.2 第二重:递归组合的力量

// 利用递归处理复杂树形结构
public class FileSystemComponent {
// ... 基础方法
// 递归查找
public FileSystemComponent find(String name) {
if (this.getName().equals(name)) {
return this;
}
if (this instanceof Directory) {
Directory dir = (Directory) this;
for (FileSystemComponent child : dir.getChildren()) {
FileSystemComponent result = child.find(name);
if (result != null) {
return result;
}
}
}
return null;
}
// 递归统计
public int countFiles() {
if (this instanceof File) {
return 1;
}
int count = 0;
if (this instanceof Directory) {
Directory dir = (Directory) this;
for (FileSystemComponent child : dir.getChildren()) {
count += child.countFiles();
}
}
return count;
}
}

3.3 第三重:组合迭代器

// 为组合结构提供迭代器
public interface ComponentIterator extends Iterator<FileSystemComponent> {boolean hasNext();FileSystemComponent next();}public class DepthFirstIterator implements ComponentIterator {private Stack<FileSystemComponent> stack = new Stack<>();public DepthFirstIterator(FileSystemComponent root) {stack.push(root);}@Overridepublic boolean hasNext() {return !stack.isEmpty();}@Overridepublic FileSystemComponent next() {if (!hasNext()) {throw new NoSuchElementException();}FileSystemComponent component = stack.pop();if (component instanceof Directory) {Directory dir = (Directory) component;// 逆序压栈,保证正序遍历for (int i = dir.getChildCount() - 1; i >= 0; i--) {stack.push(dir.getChild(i));}}return component;}}

4. 实战案例:完整的组织架构系统

// 组织组件接口
public interface OrganizationComponent {
String getName();
String getPosition();
double getSalary();
void display();
void add(OrganizationComponent component);
void remove(OrganizationComponent component);
OrganizationComponent getChild(int index);
// 业务方法
double calculateTotalSalary();
int countEmployees();
void printOrganizationChart();
}
// 员工类 - 叶子节点
public class Employee implements OrganizationComponent {
private String name;
private String position;
private double salary;
public Employee(String name, String position, double salary) {
this.name = name;
this.position = position;
this.salary = salary;
}
@Override
public String getName() {
return name;
}
@Override
public String getPosition() {
return position;
}
@Override
public double getSalary() {
return salary;
}
@Override
public void display() {
System.out.println("员工: " + name + " - " + position + " - 薪资: " + salary);
}
@Override
public double calculateTotalSalary() {
return salary;
}
@Override
public int countEmployees() {
return 1;
}
@Override
public void printOrganizationChart() {
System.out.println("  └── " + name + " (" + position + ")");
}
@Override
public void add(OrganizationComponent component) {
throw new UnsupportedOperationException("员工不能有下属");
}
@Override
public void remove(OrganizationComponent component) {
throw new UnsupportedOperationException("员工不能删除下属");
}
@Override
public OrganizationComponent getChild(int index) {
throw new UnsupportedOperationException("员工没有下属");
}
}
// 部门类 - 容器节点
public class Department implements OrganizationComponent {
private String name;
private String manager;
private List<OrganizationComponent> children;public Department(String name, String manager) {this.name = name;this.manager = manager;this.children = new ArrayList<>();}@Overridepublic String getName() {return name;}@Overridepublic String getPosition() {return "部门经理: " + manager;}@Overridepublic double getSalary() {// 部门的薪资是下属薪资的总和return calculateTotalSalary();}@Overridepublic void display() {System.out.println("部门: " + name + " - " + getPosition());for (OrganizationComponent child : children) {child.display();}}@Overridepublic double calculateTotalSalary() {double total = 0;for (OrganizationComponent child : children) {total += child.calculateTotalSalary();}return total;}@Overridepublic int countEmployees() {int count = 0;for (OrganizationComponent child : children) {count += child.countEmployees();}return count;}@Overridepublic void printOrganizationChart() {System.out.println(name + " (" + manager + ")");for (OrganizationComponent child : children) {System.out.print("  ");child.printOrganizationChart();}}@Overridepublic void add(OrganizationComponent component) {children.add(component);}@Overridepublic void remove(OrganizationComponent component) {children.remove(component);}@Overridepublic OrganizationComponent getChild(int index) {if (index >= 0 && index < children.size()) {return children.get(index);}return null;}// 部门特有的方法public int getEmployeeCount() {return countEmployees();}public List<OrganizationComponent> getSubDepartments() {return children.stream().filter(child -> child instanceof Department).collect(Collectors.toList());}public List<OrganizationComponent> getEmployees() {return children.stream().filter(child -> child instanceof Employee).collect(Collectors.toList());}}// 公司类 - 根容器public class Company implements OrganizationComponent {private String name;private String ceo;private List<OrganizationComponent> departments;public Company(String name, String ceo) {this.name = name;this.ceo = ceo;this.departments = new ArrayList<>();}@Overridepublic String getName() {return name;}@Overridepublic String getPosition() {return "CEO: " + ceo;}@Overridepublic double getSalary() {return calculateTotalSalary();}@Overridepublic void display() {System.out.println("公司: " + name);System.out.println("CEO: " + ceo);System.out.println("=== 组织架构 ===");for (OrganizationComponent dept : departments) {dept.display();}}@Overridepublic double calculateTotalSalary() {double total = 0;for (OrganizationComponent dept : departments) {total += dept.calculateTotalSalary();}return total;}@Overridepublic int countEmployees() {int count = 0;for (OrganizationComponent dept : departments) {count += dept.countEmployees();}return count;}@Overridepublic void printOrganizationChart() {System.out.println("=== " + name + " 组织架构图 ===");System.out.println("CEO: " + ceo);for (OrganizationComponent dept : departments) {dept.printOrganizationChart();}}@Overridepublic void add(OrganizationComponent component) {if (component instanceof Department) {departments.add(component);} else {throw new IllegalArgumentException("公司只能添加部门");}}@Overridepublic void remove(OrganizationComponent component) {departments.remove(component);}@Overridepublic OrganizationComponent getChild(int index) {if (index >= 0 && index < departments.size()) {return departments.get(index);}return null;}// 公司特有的方法public void generateSalaryReport() {System.out.println("=== " + name + " 薪资报告 ===");System.out.println("总员工数: " + countEmployees());System.out.println("总薪资支出: " + calculateTotalSalary());System.out.println("平均薪资: " + calculateTotalSalary() / countEmployees());for (OrganizationComponent dept : departments) {Department department = (Department) dept;System.out.println("\n部门: " + department.getName());System.out.println("  员工数: " + department.countEmployees());System.out.println("  部门薪资: " + department.calculateTotalSalary());}}public Department findDepartment(String name) {for (OrganizationComponent dept : departments) {Department department = (Department) dept;if (department.getName().equals(name)) {return department;}}return null;}}// 使用示例public class OrganizationDemo {public static void main(String[] args) {// 创建公司Company company = new Company("科技有限公司", "张总裁");// 创建技术部门Department techDept = new Department("技术部", "李经理");techDept.add(new Employee("王工程师", "高级工程师", 15000));techDept.add(new Employee("赵工程师", "工程师", 12000));techDept.add(new Employee("钱工程师", "初级工程师", 8000));// 创建销售部门Department salesDept = new Department("销售部", "陈经理");salesDept.add(new Employee("周销售", "销售总监", 13000));salesDept.add(new Employee("吴销售", "销售代表", 9000));// 创建市场部门及其子部门Department marketDept = new Department("市场部", "孙经理");Department digitalMarketing = new Department("数字营销组", "郑组长");digitalMarketing.add(new Employee("冯专员", "SEO专员", 8500));digitalMarketing.add(new Employee("魏专员", "内容专员", 8200));marketDept.add(digitalMarketing);marketDept.add(new Employee("蒋专员", "品牌专员", 8800));// 组装公司结构company.add(techDept);company.add(salesDept);company.add(marketDept);// 统一处理System.out.println("=== 统一显示 ===");company.display();System.out.println("\n=== 组织架构图 ===");company.printOrganizationChart();System.out.println("\n=== 薪资报告 ===");company.generateSalaryReport();// 客户端无需区分具体类型System.out.println("\n=== 统计信息 ===");System.out.println("公司总员工数: " + company.countEmployees());System.out.println("公司总薪资: " + company.calculateTotalSalary());// 递归查找Department foundDept = company.findDepartment("技术部");if (foundDept != null) {System.out.println("\n找到部门: " + foundDept.getName());System.out.println("部门员工数: " + foundDept.countEmployees());}}}

5. Spring框架中的组合模式

Spring框架中大量使用了组合模式的思想:

5.1 Spring Security的配置组合

// 模拟Spring Security的配置组合
public interface SecurityConfig {
void configure();
String getName();
void addConfig(SecurityConfig config);
List<SecurityConfig> getChildren();}// 具体的安全配置@Componentpublic class HttpSecurityConfig implements SecurityConfig {private List<SecurityConfig> configs = new ArrayList<>();private String name;public HttpSecurityConfig(String name) {this.name = name;}@Overridepublic void configure() {System.out.println("配置HTTP安全: " + name);for (SecurityConfig config : configs) {config.configure();}}@Overridepublic String getName() {return name;}@Overridepublic void addConfig(SecurityConfig config) {configs.add(config);}@Overridepublic List<SecurityConfig> getChildren() {return new ArrayList<>(configs);}// HTTP安全特有的方法public HttpSecurityConfig authorizeRequests() {addConfig(new AuthorizeRequestsConfig());return this;}public HttpSecurityConfig formLogin() {addConfig(new FormLoginConfig());return this;}public HttpSecurityConfig logout() {addConfig(new LogoutConfig());return this;}}// 具体的配置项@Componentpublic class AuthorizeRequestsConfig implements SecurityConfig {@Overridepublic void configure() {System.out.println("  配置授权规则");}@Overridepublic String getName() {return "authorizeRequests";}@Overridepublic void addConfig(SecurityConfig config) {throw new UnsupportedOperationException("叶子配置不能添加子配置");}@Overridepublic List<SecurityConfig> getChildren() {return Collections.emptyList();}}@Componentpublic class FormLoginConfig implements SecurityConfig {@Overridepublic void configure() {System.out.println("  配置表单登录");}@Overridepublic String getName() {return "formLogin";}@Overridepublic void addConfig(SecurityConfig config) {throw new UnsupportedOperationException("叶子配置不能添加子配置");}@Overridepublic List<SecurityConfig> getChildren() {return Collections.emptyList();}}// 安全配置构建器@Configuration@EnableWebSecuritypublic class SecurityConfiguration {@Beanpublic SecurityConfig securityConfig() {HttpSecurityConfig httpSecurity = new HttpSecurityConfig("httpSecurity");httpSecurity.authorizeRequests().formLogin().logout();return httpSecurity;}@Beanpublic SecurityConfigManager securityConfigManager() {return new SecurityConfigManager();}}// 安全配置管理器@Componentpublic class SecurityConfigManager {private List<SecurityConfig> configs = new ArrayList<>();@Autowiredpublic SecurityConfigManager(SecurityConfig... configs) {this.configs.addAll(Arrays.asList(configs));}public void configureAll() {System.out.println("=== 开始配置安全 ===");for (SecurityConfig config : configs) {config.configure();}System.out.println("=== 安全配置完成 ===");}public void addConfig(SecurityConfig config) {configs.add(config);}public List<SecurityConfig> getAllConfigs() {List<SecurityConfig> allConfigs = new ArrayList<>();collectConfigs(configs, allConfigs);return allConfigs;}private void collectConfigs(List<SecurityConfig> current, List<SecurityConfig> result) {for (SecurityConfig config : current) {result.add(config);collectConfigs(config.getChildren(), result);}}}

5.2 Spring Bean定义的组合

// 模拟Spring Bean定义组合
public interface BeanDefinition {
String getBeanName();
Class<?> getBeanClass();void validate();List<BeanDefinition> getDependsOn();}// 具体的Bean定义public class RootBeanDefinition implements BeanDefinition {private String beanName;private Class<?> beanClass;private List<BeanDefinition> dependencies = new ArrayList<>();public RootBeanDefinition(String beanName, Class<?> beanClass) {this.beanName = beanName;this.beanClass = beanClass;}@Overridepublic String getBeanName() {return beanName;}@Overridepublic Class<?> getBeanClass() {return beanClass;}@Overridepublic void validate() {System.out.println("验证Bean定义: " + beanName);for (BeanDefinition dependency : dependencies) {dependency.validate();}}@Overridepublic List<BeanDefinition> getDependsOn() {return new ArrayList<>(dependencies);}public void addDependency(BeanDefinition dependency) {dependencies.add(dependency);}}// Bean定义注册表@Componentpublic class BeanDefinitionRegistry {private Map<String, BeanDefinition> beanDefinitions = new ConcurrentHashMap<>();public void registerBeanDefinition(String name, BeanDefinition definition) {beanDefinitions.put(name, definition);}public BeanDefinition getBeanDefinition(String name) {return beanDefinitions.get(name);}public void validateAll() {System.out.println("=== 开始验证所有Bean定义 ===");for (BeanDefinition definition : beanDefinitions.values()) {definition.validate();}}public List<String> getBeanDependencyTree(String beanName) {List<String> tree = new ArrayList<>();buildDependencyTree(beanName, tree, 0);return tree;}private void buildDependencyTree(String beanName, List<String> tree, int level) {BeanDefinition definition = beanDefinitions.get(beanName);if (definition == null) return;String indent = "  ".repeat(level);tree.add(indent + beanName);for (BeanDefinition dependency : definition.getDependsOn()) {buildDependencyTree(dependency.getBeanName(), tree, level + 1);}}}

6. 组合模式的进阶用法

6.1 访问者模式与组合模式结合

// 访问者接口
public interface ComponentVisitor {
void visit(File file);
void visit(Directory directory);
void visit(Company company);
void visit(Department department);
void visit(Employee employee);
}
// 具体的访问者
public class SalaryReportVisitor implements ComponentVisitor {
private double totalSalary = 0;
private int totalEmployees = 0;
@Override
public void visit(File file) {
// 文件不需要处理
}
@Override
public void visit(Directory directory) {
// 目录本身没有薪资
}
@Override
public void visit(Company company) {
System.out.println("=== 公司薪资报告 ===");
System.out.println("公司: " + company.getName());
}
@Override
public void visit(Department department) {
System.out.println("部门: " + department.getName() +
" - 员工数: " + department.countEmployees() +
" - 总薪资: " + department.calculateTotalSalary());
}
@Override
public void visit(Employee employee) {
totalSalary += employee.getSalary();
totalEmployees++;
System.out.println("  员工: " + employee.getName() +
" - 职位: " + employee.getPosition() +
" - 薪资: " + employee.getSalary());
}
public void printSummary() {
System.out.println("=== 报告总结 ===");
System.out.println("总员工数: " + totalEmployees);
System.out.println("总薪资: " + totalSalary);
System.out.println("平均薪资: " + (totalEmployees > 0 ? totalSalary / totalEmployees : 0));
}
}
// 在组件接口中添加接受访问者的方法
public interface OrganizationComponent {
// ... 原有方法
void accept(ComponentVisitor visitor);
}
// 在具体组件中实现accept方法
public class Employee implements OrganizationComponent {
// ... 原有实现
@Override
public void accept(ComponentVisitor visitor) {
visitor.visit(this);
}
}
public class Department implements OrganizationComponent {
// ... 原有实现
@Override
public void accept(ComponentVisitor visitor) {
visitor.visit(this);
for (OrganizationComponent child : children) {
child.accept(visitor);
}
}
}
public class Company implements OrganizationComponent {
// ... 原有实现
@Override
public void accept(ComponentVisitor visitor) {
visitor.visit(this);
for (OrganizationComponent dept : departments) {
dept.accept(visitor);
}
}
}
// 使用访问者
public class VisitorDemo {
public static void main(String[] args) {
Company company = createCompany();
SalaryReportVisitor visitor = new SalaryReportVisitor();
company.accept(visitor);
visitor.printSummary();
}
private static Company createCompany() {
// 创建公司结构的代码...
return new Company(" demo公司", "demoCEO");
}
}

6.2 组合模式与建造者模式结合

// 组合建造者
public class OrganizationBuilder {
private OrganizationComponent root;
public OrganizationBuilder company(String name, String ceo) {
root = new Company(name, ceo);
return this;
}
public OrganizationBuilder department(String name, String manager) {
if (root == null) {
throw new IllegalStateException("请先创建公司");
}
Department dept = new Department(name, manager);
root.add(dept);
return this;
}
public OrganizationBuilder employee(String name, String position, double salary) {
if (root == null) {
throw new IllegalStateException("请先创建公司");
}
// 找到最后一个部门添加员工
OrganizationComponent lastDept = findLastDepartment(root);
if (lastDept != null) {
lastDept.add(new Employee(name, position, salary));
} else {
throw new IllegalStateException("请先创建部门");
}
return this;
}
private OrganizationComponent findLastDepartment(OrganizationComponent component) {
if (component instanceof Company) {
Company company = (Company) component;
List<OrganizationComponent> depts = company.getChildren();return depts.isEmpty() ? null : depts.get(depts.size() - 1);} else if (component instanceof Department) {Department dept = (Department) component;List<OrganizationComponent> children = dept.getChildren();// 查找最后一个部门for (int i = children.size() - 1; i >= 0; i--) {OrganizationComponent child = children.get(i);if (child instanceof Department) {return child;}}return dept;}return null;}public OrganizationComponent build() {return root;}}// 流畅的API使用public class BuilderDemo {public static void main(String[] args) {OrganizationComponent company = new OrganizationBuilder().company("科技有限公司", "张总裁").department("技术部", "李经理").employee("王工程师", "高级工程师", 15000).employee("赵工程师", "工程师", 12000).department("销售部", "陈经理").employee("周销售", "销售总监", 13000).employee("吴销售", "销售代表", 9000).build();company.display();}}

7. 组合模式 vs 其他模式

7.1 组合模式 vs 装饰器模式

7.2 组合模式 vs 享元模式

  • 组合模式:处理树形结构,关注对象间的层次关系
  • 享元模式:共享对象以减少内存使用,关注对象的内在状态共享

7.3 组合模式 vs 迭代器模式

8. 总结与思考

8.1 组合模式的优点

  1. 统一处理:客户端可以一致地处理单个对象和对象组合
  2. 简化客户端:客户端不需要关心处理的是单个对象还是整个结构
  3. 易于扩展:新增组件类型很容易,符合开闭原则
  4. 灵活的结构:可以构建复杂的树形结构

8.2 组合模式的缺点

  1. 设计较复杂:需要正确识别出叶子和容器节点
  2. 类型系统限制:在类型检查严格的语言中实现可能较复杂
  3. 性能考虑:深度递归可能影响性能
  4. 叶子节点限制:叶子节点需要实现一些无意义的方法

8.3 设计思考

组合模式的本质是**“递归组合”**。它通过统一的接口让客户端可以无差别地处理单个对象和对象组合,从而简化了复杂树形结构的处理。

深入思考的角度

“组合模式的核心价值在于它提供了一种处理树形结构的优雅方式。它通过递归组合和统一接口,让复杂的层次结构变得简单可控。组合模式是’部分-整体’思维在面向对象设计中的完美体现。”

在实际应用中,组合模式有很多优秀的实践:

从系统设计的角度看,组合模式特别适合以下场景:

最佳实践建议

  1. 仔细设计组件接口,确保它适用于所有类型的组件
  2. 考虑使用透明式还是安全式组合模式
  3. 为组合结构提供合适的迭代器
  4. 考虑与访问者模式结合以添加新操作
  5. 注意递归深度,避免栈溢出

使用场景判断


下一篇预告:设计模式手册011 - 享元模式:如何通过共享技术有效地支持大量细粒度对象?


版权声明:本文为CSDN博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

http://www.jsqmd.com/news/312236/

相关文章:

  • Java实习模拟面试实录:Redis原子性、Spring循环依赖与MySQL回表深度解析 —— 创新零售后端一面(40分钟)
  • 2026年评价高的深圳防水太阳能光伏板/深圳非标定制太阳能光伏板用户口碑认可参考(高评价)
  • 2026年靠谱的床单洗涤设备/消防服洗涤设备厂家推荐与选择指南
  • Pencil.dev 架构深度剖析:基于 MCP 协议的代理式设计与工程同构原理(2)
  • 2026年口碑好的高品质气压棒/防静电气压棒厂家专业度参考(精选)
  • 2026年比较好的大管径缩管机/扁型管缩管机行业内知名厂家推荐
  • 盘点工业废水第三方托管运营加工厂合作案例多的企业排名,嘉佰晟环境在列
  • JS截屏内容粘贴到UEDITOR的ELECTRON版本如何生成缩略图?
  • 2026年AI智能办公鼠标排名出炉,南方网通上榜原因分析
  • 2026年热门的建筑玻璃/家装玻璃优质厂商精选推荐(口碑)
  • 聊聊2026年杭州金华广州Starlink防水电源线生产企业,哪家口碑好
  • P1957 口算练习题
  • Starlink防水电源线供应商怎么选,分享优质品牌排名
  • 2026年推荐高档商业空间装修专业公司,口碑好的有哪些
  • 2026年靠谱的埋入式陶瓷加热板/高温陶瓷加热板厂家选购参考汇总
  • Python修改pip install 指定安装包的路径和默认镜像源 - 实践
  • 聊聊潜水推流器,蓝奥环保优质生产商产品特色解读
  • 2026年知名的汽车吸尘器/无线吸尘器厂家热卖产品推荐(近期)
  • Starlink防水电源线制造企业哪家好,深圳东莞优质厂家盘点
  • 二氧化碳供应商市场观察:服务能力与可靠性参考,汽化器/真空管/液氮速冻机/液氮/制氧机/储罐,二氧化碳供应商推荐榜单
  • 2026年长三角电竞酒店区域代理排名,竞悦电竞酒店靠谱之选
  • 绵阳实验学校新排行:这些学校教育实力不容小觑,高中/中学/名办高中/学校/实验学校/高中复读学校,实验学校直销厂家排行
  • 2026年婚庆篷房布制造商排名,质量有保障的品牌怎么选择
  • 2026年评价高的加热管电热管生产设备/数控电热管生产设备值得信赖厂家推荐(精选)
  • 2026年口碑好的加胶玻璃/防火中空玻璃优质厂商精选推荐(口碑)
  • 2026成都卤菜火锅社区店:美味与氛围并存,特色美食/社区火锅/火锅/美食/老火锅/火锅店/烧菜火锅,卤菜火锅品牌排行榜
  • 2026年四川iso27001认证咨询优质机构推荐榜:iso9001认证、业务连续性管理体系认证、人工智能管理体系认证选择指南
  • AI智能分析系统在明厨亮灶的应用方案
  • 2026年知名的28寸本安型LCD显示器/43寸本安型LCD显示器厂家热卖产品推荐(近期)
  • 2026年如何学习网络安全?网络安全学习路线