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

设计模式-组合模式详解

组合模式详解

目录

  1. 组合模式简介
  2. 核心流程
  3. 重难点分析
  4. Spring中的源码分析
  5. 具体使用场景
  6. 面试高频点

组合模式简介

定义

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

核心思想

  • 统一接口:叶子节点和组合节点使用相同的接口
  • 递归结构:支持树形结构的递归操作
  • 透明性:客户端无需区分叶子节点和组合节点
  • 整体-部分:将部分对象组合成整体对象

模式结构

  • Component(抽象构件):为组合中的对象声明接口,在适当情况下实现所有类共有接口的默认行为
  • Leaf(叶子构件):在组合中表示叶子节点对象,叶子节点没有子节点
  • Composite(组合构件):定义有子部件的那些部件的行为,存储子部件,在Component接口中实现与子部件有关的操作

核心流程

组合模式流程图

操作流程
组合结构
统一接口调用
递归处理
结果聚合
根节点Composite
子节点Composite
叶子节点Leaf
叶子节点Leaf
客户端
创建组合结构
添加叶子节点
添加组合节点
调用叶子操作
调用组合操作
遍历子节点
递归调用子节点操作
返回结果

基本实现流程

1. 定义抽象构件
// 抽象构件
public abstract class Component {protected String name;public Component(String name) {this.name = name;}// 公共操作public abstract void operation();// 组合相关操作(默认实现为空)public void add(Component component) {throw new UnsupportedOperationException("不支持添加操作");}public void remove(Component component) {throw new UnsupportedOperationException("不支持删除操作");}public Component getChild(int index) {throw new UnsupportedOperationException("不支持获取子节点操作");}public String getName() {return name;}
}
2. 实现叶子构件
// 叶子构件
public class Leaf extends Component {public Leaf(String name) {super(name);}@Overridepublic void operation() {System.out.println("叶子节点 " + name + " 执行操作");}
}
3. 实现组合构件
// 组合构件
public class Composite extends Component {private List<Component> children = new ArrayList<>();public Composite(String name) {super(name);}@Overridepublic void operation() {System.out.println("组合节点 " + name + " 执行操作");// 递归调用子节点的操作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) {if (index >= 0 && index < children.size()) {return children.get(index);}return null;}public List<Component> getChildren() {return new ArrayList<>(children);}
}
4. 客户端使用
public class Client {public static void main(String[] args) {// 创建根节点Composite root = new Composite("根目录");// 创建子节点Composite folder1 = new Composite("文件夹1");Composite folder2 = new Composite("文件夹2");// 创建叶子节点Leaf file1 = new Leaf("文件1.txt");Leaf file2 = new Leaf("文件2.txt");Leaf file3 = new Leaf("文件3.txt");// 构建树形结构root.add(folder1);root.add(folder2);root.add(file1);folder1.add(file2);folder2.add(file3);// 执行操作root.operation();}
}

重难点分析

重难点1:透明式组合模式 vs 安全式组合模式

问题描述

如何设计组合模式的接口,平衡透明性和安全性。

解决方案
// 透明式组合模式(推荐)
public abstract class Component {protected String name;public Component(String name) {this.name = name;}public abstract void operation();// 组合相关操作,叶子节点抛出异常public void add(Component component) {throw new UnsupportedOperationException("叶子节点不支持添加操作");}public void remove(Component component) {throw new UnsupportedOperationException("叶子节点不支持删除操作");}public Component getChild(int index) {throw new UnsupportedOperationException("叶子节点不支持获取子节点操作");}
}// 安全式组合模式
public abstract class Component {protected String name;public Component(String name) {this.name = name;}public abstract void operation();// 不包含组合相关操作
}public abstract class Composite extends Component {protected List<Component> children = new ArrayList<>();public Composite(String name) {super(name);}public abstract void add(Component component);public abstract void remove(Component component);public abstract Component getChild(int index);
}// 使用建议:优先使用透明式,客户端代码更简洁

重难点2:递归操作的性能优化

问题描述

在深层嵌套的组合结构中,递归操作可能导致性能问题。

解决方案
// 1. 使用迭代代替递归
public class Composite extends Component {private List<Component> children = new ArrayList<>();@Overridepublic void operation() {System.out.println("组合节点 " + name + " 执行操作");// 使用栈进行迭代遍历Stack<Component> stack = new Stack<>();for (Component child : children) {stack.push(child);}while (!stack.isEmpty()) {Component component = stack.pop();component.operation();if (component instanceof Composite) {Composite composite = (Composite) component;for (Component child : composite.getChildren()) {stack.push(child);}}}}
}// 2. 缓存计算结果
public abstract class Component {protected String name;protected boolean calculated = false;protected Object cachedResult;public Component(String name) {this.name = name;}public Object getResult() {if (!calculated) {cachedResult = calculate();calculated = true;}return cachedResult;}protected abstract Object calculate();public void invalidateCache() {calculated = false;cachedResult = null;}
}// 3. 使用访问者模式优化遍历
public interface Visitor {void visit(Leaf leaf);void visit(Composite composite);
}public class OperationVisitor implements Visitor {@Overridepublic void visit(Leaf leaf) {System.out.println("访问叶子节点: " + leaf.getName());}@Overridepublic void visit(Composite composite) {System.out.println("访问组合节点: " + composite.getName());for (Component child : composite.getChildren()) {child.accept(this);}}
}public abstract class Component {public abstract void accept(Visitor visitor);
}

重难点3:组合结构的动态管理

问题描述

如何在运行时动态添加、删除、修改组合结构。

解决方案
// 1. 支持动态结构的组合模式
public class DynamicComposite extends Component {private List<Component> children = new ArrayList<>();private Map<String, Component> childMap = new HashMap<>();public DynamicComposite(String name) {super(name);}@Overridepublic void add(Component component) {children.add(component);childMap.put(component.getName(), component);// 通知观察者notifyObservers("ADD", component);}@Overridepublic void remove(Component component) {children.remove(component);childMap.remove(component.getName());// 通知观察者notifyObservers("REMOVE", component);}public Component findByName(String name) {return childMap.get(name);}public void move(Component component, Component newParent) {if (component instanceof DynamicComposite) {DynamicComposite oldParent = findParent(component);if (oldParent != null) {oldParent.remove(component);}((DynamicComposite) newParent).add(component);}}private DynamicComposite findParent(Component component) {for (Component child : children) {if (child == component) {return this;}if (child instanceof DynamicComposite) {DynamicComposite result = ((DynamicComposite) child).findParent(component);if (result != null) {return result;}}}return null;}// 观察者模式支持private List<CompositeObserver> observers = new ArrayList<>();public void addObserver(CompositeObserver observer) {observers.add(observer);}private void notifyObservers(String action, Component component) {for (CompositeObserver observer : observers) {observer.onComponentChanged(action, component);}}
}// 2. 支持撤销操作的组合模式
public class UndoableComposite extends Component {private List<Component> children = new ArrayList<>();private Stack<CompositeCommand> commandHistory = new Stack<>();public void addWithUndo(Component component) {AddCommand command = new AddCommand(this, component);command.execute();commandHistory.push(command);}public void removeWithUndo(Component component) {RemoveCommand command = new RemoveCommand(this, component);command.execute();commandHistory.push(command);}public void undo() {if (!commandHistory.isEmpty()) {CompositeCommand command = commandHistory.pop();command.undo();}}
}// 命令接口
public interface CompositeCommand {void execute();void undo();
}// 添加命令
public class AddCommand implements CompositeCommand {private UndoableComposite parent;private Component child;public AddCommand(UndoableComposite parent, Component child) {this.parent = parent;this.child = child;}@Overridepublic void execute() {parent.add(child);}@Overridepublic void undo() {parent.remove(child);}
}

重难点4:组合模式的内存管理

问题描述

在复杂的组合结构中,如何避免内存泄漏和循环引用。

解决方案
// 1. 使用弱引用避免循环引用
public class WeakComposite extends Component {private List<WeakReference<Component>> children = new ArrayList<>();private Component parent;public void add(Component component) {children.add(new WeakReference<>(component));if (component instanceof WeakComposite) {((WeakComposite) component).parent = this;}}@Overridepublic void operation() {System.out.println("组合节点 " + name + " 执行操作");// 清理失效的弱引用children.removeIf(ref -> ref.get() == null);for (WeakReference<Component> ref : children) {Component child = ref.get();if (child != null) {child.operation();}}}
}// 2. 实现自动清理机制
public class AutoCleanupComposite extends Component {private List<Component> children = new ArrayList<>();private boolean disposed = false;@Overridepublic void operation() {if (disposed) {throw new IllegalStateException("组件已被销毁");}System.out.println("组合节点 " + name + " 执行操作");for (Component child : children) {child.operation();}}public void dispose() {if (!disposed) {// 递归销毁子组件for (Component child : children) {if (child instanceof AutoCleanupComposite) {((AutoCleanupComposite) child).dispose();}}children.clear();disposed = true;}}@Overrideprotected void finalize() throws Throwable {try {dispose();} finally {super.finalize();}}
}// 3. 使用对象池管理组件
public class ComponentPool {private final Queue<Component> pool = new ConcurrentLinkedQueue<>();private final int maxSize;public ComponentPool(int maxSize) {this.maxSize = maxSize;}public Component acquire() {Component component = pool.poll();if (component == null) {component = new Leaf("PooledComponent");}return component;}public void release(Component component) {if (pool.size() < maxSize) {// 重置组件状态component.reset();pool.offer(component);}}
}

Spring中的源码分析

Spring Bean的层次结构

// BeanDefinition接口作为抽象构件
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;void setParentName(@Nullable String parentName);@NullableString getParentName();void setBeanClassName(@Nullable String beanClassName);@NullableString getBeanClassName();void setScope(@Nullable String scope);@NullableString getScope();void setLazyInit(boolean lazyInit);boolean isLazyInit();void setDependsOn(@Nullable String... dependsOn);@NullableString[] getDependsOn();void setFactoryBeanName(@Nullable String factoryBeanName);@NullableString getFactoryBeanName();void setFactoryMethodName(@Nullable String factoryMethodName);@NullableString getFactoryMethodName();
}// 具体实现
public class GenericBeanDefinition extends AbstractBeanDefinition {@Nullableprivate String parentName;public GenericBeanDefinition() {super();}public GenericBeanDefinition(BeanDefinition original) {super(original);}@Overridepublic void setParentName(@Nullable String parentName) {this.parentName = parentName;}@Override@Nullablepublic String getParentName() {return this.parentName;}@Overridepublic AbstractBeanDefinition cloneBeanDefinition() {return new GenericBeanDefinition(this);}
}

Spring Security的权限层次结构

// ConfigAttribute接口
public interface ConfigAttribute extends Serializable {String getAttribute();
}// 具体实现
public class SecurityConfig implements ConfigAttribute {private final String config;public SecurityConfig(String config) {Assert.hasText(config, "You must provide a configuration attribute");this.config = config;}@Overridepublic String getAttribute() {return this.config;}@Overridepublic boolean equals(Object obj) {if (obj instanceof SecurityConfig) {SecurityConfig that = (SecurityConfig) obj;return this.config.equals(that.config);}return false;}@Overridepublic int hashCode() {return this.config.hashCode();}@Overridepublic String toString() {return this.config;}
}// 权限组合
public class SecurityConfigCollection implements ConfigAttribute {private final Collection<ConfigAttribute> configAttributes;public SecurityConfigCollection(Collection<ConfigAttribute> configAttributes) {this.configAttributes = configAttributes;}@Overridepublic String getAttribute() {return configAttributes.stream().map(ConfigAttribute::getAttribute).collect(Collectors.joining(", "));}public Collection<ConfigAttribute> getConfigAttributes() {return configAttributes;}
}

Spring MVC的HandlerMapping层次结构

// HandlerMapping接口
public interface HandlerMapping {String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping";String BEST_MATCHING_PATTERN_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingPattern";String INTROSPECT_TYPE_LEVEL_MAPPING = HandlerMapping.class.getName() + ".introspectTypeLevelMapping";String URI_TEMPLATE_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".uriTemplateVariables";String MATRIX_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".matrixVariables";String PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE = HandlerMapping.class.getName() + ".producibleMediaTypes";String HANDLER_ATTRIBUTE = HandlerMapping.class.getName() + ".handler";@NullableHandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}// 抽象实现
public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport implements HandlerMapping, Ordered {private final Map<String, Object> urlMap = new LinkedHashMap<>();private final Map<PathPattern, Object> pathPatternMap = new LinkedHashMap<>();@Override@Nullablepublic final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {Object handler = getHandlerInternal(request);if (handler == null) {handler = getDefaultHandler();}if (handler == null) {return null;}if (handler instanceof String) {String handlerName = (String) handler;handler = obtainApplicationContext().getBean(handlerName);}HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);if (logger.isTraceEnabled()) {logger.trace("Mapped to " + handler);} else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.REQUEST)) {logger.debug("Mapped to " + handler);}return executionChain;}@Nullableprotected abstract Object getHandlerInternal(HttpServletRequest request) throws Exception;
}

Spring AOP的切面层次结构

// Pointcut接口
public interface Pointcut {ClassFilter getClassFilter();MethodMatcher getMethodMatcher();Pointcut TRUE = TruePointcut.INSTANCE;
}// 具体实现
public class AspectJExpressionPointcut implements Pointcut, ClassFilter, MethodMatcher, Serializable {private static final Set<PointcutPrimitive> SUPPORTED_PRIMITIVES = new HashSet<>();static {SUPPORTED_PRIMITIVES.add(PointcutPrimitive.EXECUTION);SUPPORTED_PRIMITIVES.add(PointcutPrimitive.ARGS);SUPPORTED_PRIMITIVES.add(PointcutPrimitive.REFERENCE);SUPPORTED_PRIMITIVES.add(PointcutPrimitive.THIS);SUPPORTED_PRIMITIVES.add(PointcutPrimitive.TARGET);SUPPORTED_PRIMITIVES.add(PointcutPrimitive.WITHIN);SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_ANNOTATION);SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_WITHIN);SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_ARGS);SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_TARGET);}private String expression;private PointcutExpression pointcutExpression;private ClassFilter classFilter;private MethodMatcher methodMatcher;public void setExpression(@Nullable String expression) {this.expression = expression;}@Overridepublic ClassFilter getClassFilter() {return this.classFilter;}@Overridepublic MethodMatcher getMethodMatcher() {return this.methodMatcher;}@Overridepublic boolean matches(Class<?> clazz) {return this.classFilter.matches(clazz);}@Overridepublic boolean matches(Method method, Class<?> targetClass) {return this.methodMatcher.matches(method, targetClass);}
}

具体使用场景

1. 文件系统

// 文件系统组件
public abstract class FileSystemComponent {protected String name;protected long size;public FileSystemComponent(String name) {this.name = name;}public abstract void display();public abstract long getSize();public String getName() {return name;}
}// 文件(叶子节点)
public class File extends FileSystemComponent {private String content;public File(String name, String content) {super(name);this.content = content;this.size = content.length();}@Overridepublic void display() {System.out.println("文件: " + name + " (大小: " + size + " 字节)");}@Overridepublic long getSize() {return size;}public String getContent() {return content;}
}// 文件夹(组合节点)
public class Directory extends FileSystemComponent {private List<FileSystemComponent> children = new ArrayList<>();public Directory(String name) {super(name);}@Overridepublic void display() {System.out.println("文件夹: " + name);for (FileSystemComponent child : children) {child.display();}}@Overridepublic long getSize() {long totalSize = 0;for (FileSystemComponent child : children) {totalSize += child.getSize();}return totalSize;}public void add(FileSystemComponent component) {children.add(component);}public void remove(FileSystemComponent component) {children.remove(component);}public List<FileSystemComponent> getChildren() {return new ArrayList<>(children);}
}// 使用示例
public class FileSystemDemo {public static void main(String[] args) {// 创建根目录Directory root = new Directory("根目录");// 创建子目录Directory documents = new Directory("文档");Directory pictures = new Directory("图片");// 创建文件File file1 = new File("readme.txt", "这是一个说明文件");File file2 = new File("config.xml", "<config></config>");File file3 = new File("photo.jpg", "图片内容");// 构建文件系统root.add(documents);root.add(pictures);root.add(file1);documents.add(file2);pictures.add(file3);// 显示文件系统root.display();System.out.println("总大小: " + root.getSize() + " 字节");}
}

2. 组织架构管理

// 员工组件
public abstract class Employee {protected String name;protected String position;protected double salary;public Employee(String name, String position, double salary) {this.name = name;this.position = position;this.salary = salary;}public abstract void showDetails();public abstract double calculateTotalSalary();public abstract void add(Employee employee);public abstract void remove(Employee employee);public String getName() {return name;}
}// 普通员工(叶子节点)
public class IndividualEmployee extends Employee {public IndividualEmployee(String name, String position, double salary) {super(name, position, salary);}@Overridepublic void showDetails() {System.out.println("员工: " + name + ", 职位: " + position + ", 薪资: " + salary);}@Overridepublic double calculateTotalSalary() {return salary;}@Overridepublic void add(Employee employee) {throw new UnsupportedOperationException("普通员工不能添加下属");}@Overridepublic void remove(Employee employee) {throw new UnsupportedOperationException("普通员工不能删除下属");}
}// 管理者(组合节点)
public class Manager extends Employee {private List<Employee> subordinates = new ArrayList<>();public Manager(String name, String position, double salary) {super(name, position, salary);}@Overridepublic void showDetails() {System.out.println("管理者: " + name + ", 职位: " + position + ", 薪资: " + salary);System.out.println("下属员工:");for (Employee subordinate : subordinates) {System.out.print("  ");subordinate.showDetails();}}@Overridepublic double calculateTotalSalary() {double total = salary;for (Employee subordinate : subordinates) {total += subordinate.calculateTotalSalary();}return total;}@Overridepublic void add(Employee employee) {subordinates.add(employee);}@Overridepublic void remove(Employee employee) {subordinates.remove(employee);}public List<Employee> getSubordinates() {return new ArrayList<>(subordinates);}
}// 使用示例
public class OrganizationDemo {public static void main(String[] args) {// 创建CEOManager ceo = new Manager("张三", "CEO", 50000);// 创建部门经理Manager techManager = new Manager("李四", "技术经理", 30000);Manager salesManager = new Manager("王五", "销售经理", 28000);// 创建普通员工IndividualEmployee dev1 = new IndividualEmployee("赵六", "开发工程师", 15000);IndividualEmployee dev2 = new IndividualEmployee("钱七", "测试工程师", 12000);IndividualEmployee sales1 = new IndividualEmployee("孙八", "销售代表", 10000);// 构建组织架构ceo.add(techManager);ceo.add(salesManager);techManager.add(dev1);techManager.add(dev2);salesManager.add(sales1);// 显示组织架构ceo.showDetails();System.out.println("总薪资支出: " + ceo.calculateTotalSalary());}
}

3. 菜单系统

// 菜单组件
public abstract class MenuComponent {protected String name;protected String description;protected double price;protected boolean vegetarian;public MenuComponent(String name, String description) {this.name = name;this.description = description;}public abstract void print();public abstract void add(MenuComponent component);public abstract void remove(MenuComponent component);public abstract MenuComponent getChild(int index);public String getName() {return name;}public String getDescription() {return description;}public double getPrice() {return price;}public boolean isVegetarian() {return vegetarian;}
}// 菜单项(叶子节点)
public class MenuItem extends MenuComponent {public MenuItem(String name, String description, double price, boolean vegetarian) {super(name, description);this.price = price;this.vegetarian = vegetarian;}@Overridepublic void print() {System.out.print("  " + name);if (vegetarian) {System.out.print("(V)");}System.out.println(", " + price);System.out.println("     -- " + description);}@Overridepublic void add(MenuComponent component) {throw new UnsupportedOperationException("菜单项不能添加子项");}@Overridepublic void remove(MenuComponent component) {throw new UnsupportedOperationException("菜单项不能删除子项");}@Overridepublic MenuComponent getChild(int index) {throw new UnsupportedOperationException("菜单项没有子项");}
}// 菜单(组合节点)
public class Menu extends MenuComponent {private List<MenuComponent> menuComponents = new ArrayList<>();public Menu(String name, String description) {super(name, description);}@Overridepublic void print() {System.out.println("\n" + name + ", " + description);System.out.println("---------------------");for (MenuComponent component : menuComponents) {component.print();}}@Overridepublic void add(MenuComponent component) {menuComponents.add(component);}@Overridepublic void remove(MenuComponent component) {menuComponents.remove(component);}@Overridepublic MenuComponent getChild(int index) {if (index >= 0 && index < menuComponents.size()) {return menuComponents.get(index);}return null;}
}// 使用示例
public class MenuDemo {public static void main(String[] args) {// 创建主菜单Menu pancakeHouseMenu = new Menu("煎饼屋菜单", "早餐菜单");Menu dinerMenu = new Menu("餐厅菜单", "午餐菜单");Menu dessertMenu = new Menu("甜点菜单", "甜点菜单");// 添加菜单项pancakeHouseMenu.add(new MenuItem("煎饼", "薄煎饼配鸡蛋", 2.99, true));pancakeHouseMenu.add(new MenuItem("华夫饼", "华夫饼配蓝莓", 3.59, true));dinerMenu.add(new MenuItem("素食汉堡", "素食汉堡配薯条", 2.99, true));dinerMenu.add(new MenuItem("培根汉堡", "培根汉堡配薯条", 3.49, false));dessertMenu.add(new MenuItem("苹果派", "苹果派配冰淇淋", 1.59, true));dessertMenu.add(new MenuItem("芝士蛋糕", "纽约芝士蛋糕", 1.99, true));// 将甜点菜单添加到餐厅菜单dinerMenu.add(dessertMenu);// 显示菜单pancakeHouseMenu.print();dinerMenu.print();}
}

4. 图形绘制系统

// 图形组件
public abstract class Graphic {protected String name;protected int x, y;public Graphic(String name, int x, int y) {this.name = name;this.x = x;this.y = y;}public abstract void draw();public abstract void move(int deltaX, int deltaY);public abstract void add(Graphic graphic);public abstract void remove(Graphic graphic);public abstract Graphic getChild(int index);public String getName() {return name;}
}// 简单图形(叶子节点)
public class Circle extends Graphic {private int radius;public Circle(String name, int x, int y, int radius) {super(name, x, y);this.radius = radius;}@Overridepublic void draw() {System.out.println("绘制圆形: " + name + " at (" + x + "," + y + ") radius=" + radius);}@Overridepublic void move(int deltaX, int deltaY) {this.x += deltaX;this.y += deltaY;}@Overridepublic void add(Graphic graphic) {throw new UnsupportedOperationException("简单图形不能添加子图形");}@Overridepublic void remove(Graphic graphic) {throw new UnsupportedOperationException("简单图形不能删除子图形");}@Overridepublic Graphic getChild(int index) {throw new UnsupportedOperationException("简单图形没有子图形");}
}public class Rectangle extends Graphic {private int width, height;public Rectangle(String name, int x, int y, int width, int height) {super(name, x, y);this.width = width;this.height = height;}@Overridepublic void draw() {System.out.println("绘制矩形: " + name + " at (" + x + "," + y + ") size=" + width + "x" + height);}@Overridepublic void move(int deltaX, int deltaY) {this.x += deltaX;this.y += deltaY;}@Overridepublic void add(Graphic graphic) {throw new UnsupportedOperationException("简单图形不能添加子图形");}@Overridepublic void remove(Graphic graphic) {throw new UnsupportedOperationException("简单图形不能删除子图形");}@Overridepublic Graphic getChild(int index) {throw new UnsupportedOperationException("简单图形没有子图形");}
}// 复合图形(组合节点)
public class CompositeGraphic extends Graphic {private List<Graphic> children = new ArrayList<>();public CompositeGraphic(String name, int x, int y) {super(name, x, y);}@Overridepublic void draw() {System.out.println("绘制复合图形: " + name + " at (" + x + "," + y + ")");for (Graphic child : children) {child.draw();}}@Overridepublic void move(int deltaX, int deltaY) {this.x += deltaX;this.y += deltaY;// 移动所有子图形for (Graphic child : children) {child.move(deltaX, deltaY);}}@Overridepublic void add(Graphic graphic) {children.add(graphic);}@Overridepublic void remove(Graphic graphic) {children.remove(graphic);}@Overridepublic Graphic getChild(int index) {if (index >= 0 && index < children.size()) {return children.get(index);}return null;}public List<Graphic> getChildren() {return new ArrayList<>(children);}
}// 使用示例
public class GraphicsDemo {public static void main(String[] args) {// 创建复合图形CompositeGraphic picture = new CompositeGraphic("图片", 0, 0);// 创建简单图形Circle circle = new Circle("圆形", 10, 10, 5);Rectangle rectangle = new Rectangle("矩形", 20, 20, 10, 8);// 创建子复合图形CompositeGraphic group = new CompositeGraphic("组", 30, 30);Circle circle2 = new Circle("圆形2", 0, 0, 3);Rectangle rectangle2 = new Rectangle("矩形2", 5, 5, 6, 4);// 构建图形层次结构picture.add(circle);picture.add(rectangle);picture.add(group);group.add(circle2);group.add(rectangle2);// 绘制图形picture.draw();// 移动图形System.out.println("\n移动图形:");picture.move(5, 5);picture.draw();}
}

面试高频点

面试知识点思维导图

组合模式面试点
基本概念
实现方式
重难点
Spring应用
设计原则
实际应用
部分-整体层次结构
统一接口
递归结构
透明性
Component抽象构件
Leaf叶子构件
Composite组合构件
客户端调用
透明式vs安全式
递归操作性能
动态管理
内存管理
BeanDefinition层次
Security权限层次
HandlerMapping层次
AOP切面层次
开闭原则
单一职责
里氏替换
组合优于继承
文件系统
组织架构
菜单系统
图形绘制

1. 组合模式的基本概念

问题:什么是组合模式?

答案要点:

  • 将对象组合成树形结构以表示"部分-整体"的层次结构
  • 使得用户对单个对象和组合对象的使用具有一致性
  • 属于结构型设计模式
  • 解决树形结构的递归操作问题
问题:组合模式有哪些角色?

答案要点:

  • Component(抽象构件):为组合中的对象声明接口
  • Leaf(叶子构件):在组合中表示叶子节点对象
  • Composite(组合构件):定义有子部件的那些部件的行为
  • Client(客户端):通过Component接口操作组合对象

2. 实现方式相关

问题:如何实现组合模式?

答案要点:

// 1. 定义抽象构件
public abstract class Component {protected String name;public Component(String name) {this.name = name;}public abstract void operation();public void add(Component component) {throw new UnsupportedOperationException("不支持添加操作");}public void remove(Component component) {throw new UnsupportedOperationException("不支持删除操作");}
}// 2. 实现叶子构件
public class Leaf extends Component {public Leaf(String name) {super(name);}@Overridepublic void operation() {System.out.println("叶子节点 " + name + " 执行操作");}
}// 3. 实现组合构件
public class Composite extends Component {private List<Component> children = new ArrayList<>();public Composite(String name) {super(name);}@Overridepublic void operation() {System.out.println("组合节点 " + name + " 执行操作");for (Component child : children) {child.operation();}}@Overridepublic void add(Component component) {children.add(component);}@Overridepublic void remove(Component component) {children.remove(component);}
}

3. 重难点问题

问题:透明式组合模式和安全式组合模式的区别?

答案要点:

  • 透明式:在Component中定义所有方法,叶子节点抛出异常
  • 安全式:只在Composite中定义组合相关方法
  • 透明式优点:客户端代码简洁,无需类型判断
  • 安全式优点:编译时类型安全,避免运行时异常
  • 推荐:优先使用透明式,客户端代码更简洁
问题:如何优化组合模式的递归操作性能?

答案要点:

// 1. 使用迭代代替递归
public void operation() {Stack<Component> stack = new Stack<>();stack.push(this);while (!stack.isEmpty()) {Component component = stack.pop();component.performOperation();if (component instanceof Composite) {for (Component child : ((Composite) component).getChildren()) {stack.push(child);}}}
}// 2. 使用访问者模式
public interface Visitor {void visit(Leaf leaf);void visit(Composite composite);
}// 3. 缓存计算结果
public abstract class Component {private boolean calculated = false;private Object cachedResult;public Object getResult() {if (!calculated) {cachedResult = calculate();calculated = true;}return cachedResult;}
}

4. Spring中的应用

问题:Spring中如何使用组合模式?

答案要点:

// 1. BeanDefinition层次结构
public interface BeanDefinition {void setParentName(String parentName);String getParentName();// ... 其他方法
}// 2. Security权限层次结构
public interface ConfigAttribute {String getAttribute();
}// 3. HandlerMapping层次结构
public interface HandlerMapping {HandlerExecutionChain getHandler(HttpServletRequest request);
}// 4. AOP切面层次结构
public interface Pointcut {ClassFilter getClassFilter();MethodMatcher getMethodMatcher();
}

5. 设计原则相关

问题:组合模式体现了哪些设计原则?

答案要点:

  • 开闭原则:可以添加新的叶子节点和组合节点
  • 单一职责:每个类只负责一个职责
  • 里氏替换:叶子节点和组合节点可以替换抽象构件
  • 组合优于继承:使用组合关系而不是继承关系

6. 实际应用场景

问题:组合模式适用于哪些场景?

答案要点:

  • 文件系统:文件和文件夹的层次结构
  • 组织架构:员工和管理者的层次结构
  • 菜单系统:菜单和菜单项的层次结构
  • 图形绘制:简单图形和复合图形的层次结构
  • XML解析:XML元素的层次结构
  • 权限管理:权限和角色的层次结构

7. 与其他模式的对比

问题:组合模式与装饰器模式的区别?

答案要点:

  • 目的:组合模式是结构组合,装饰器模式是功能增强
  • 关系:组合模式是部分-整体关系,装饰器模式是包装关系
  • 结构:组合模式是树形结构,装饰器模式是链式结构
  • 使用场景:组合模式用于层次结构,装饰器模式用于功能扩展
问题:组合模式与迭代器模式的关系?

答案要点:

  • 组合关系:组合模式经常与迭代器模式结合使用
  • 遍历需求:组合结构需要遍历所有节点
  • 实现方式:可以使用迭代器模式遍历组合结构
  • 性能优化:迭代器模式可以优化组合结构的遍历性能

总结

组合模式是一种重要的结构型设计模式,它通过将对象组合成树形结构,实现了部分-整体的层次结构,并提供了统一的接口。

核心优势

  1. 统一接口:叶子节点和组合节点使用相同接口
  2. 递归结构:支持树形结构的递归操作
  3. 透明性:客户端无需区分叶子节点和组合节点
  4. 扩展性:易于添加新的叶子节点和组合节点

注意事项

  1. 性能考虑:深层递归可能影响性能
  2. 内存管理:复杂结构需要注意内存泄漏
  3. 设计复杂度:增加了系统的复杂度
  4. 类型安全:透明式模式可能产生运行时异常

在实际开发中,组合模式特别适用于需要表示部分-整体层次结构的场景,如文件系统、组织架构、菜单系统等。通过合理使用组合模式,可以大大提高系统的灵活性和可维护性。

http://www.dtcms.com/a/398552.html

相关文章:

  • 什么是B域?
  • Android 用java程序模拟binder buffer的分配释放以及buffer的向前和向后合并
  • 专门做护肤品网站浙江立鹏建设有限公司网站
  • 电商会学着做网站呢设计师接单渠道
  • Postman 学习笔记 II:测试、断言与变量管理
  • electron设置默认应用程序
  • Flink 初体验10 分钟完成下载、安装、本地集群启动与示例作业运行
  • toLua[二] Examples 01_HelloWorld分析
  • asp源码打开网站网站页面数量
  • 安卓手机termux安装ubuntu被kill进程解决
  • java后端工程师进修ing(研一版‖day48)
  • 目标检测进化史
  • 北京做养生SPA的网站建设高端网站建设 来磐石网络
  • 网站建设有哪三部来年做那些网站能致富
  • 外贸公司网站素材产品营销文案
  • VSCode C/C++ 开发环境配置
  • FPGA自学笔记--VIVADO RAM IP核控制和使用
  • 电源——设计DCDC原理图与参数选型
  • 企业网站建设策划书 前言263云通信官方网站
  • pip config list输出为空?如何配置pip镜像源?不同方式配置有什么区别?
  • 表格工具怎么选,国产化替代方案测评(2025 全维度实测版)
  • 分布式 ID 生成方案实战指南:从选型到落地的全场景避坑手册(二)
  • 企业网站建设案例宝安三网合一网站建设
  • 做透水砖的网站vs2019可以做网站吗
  • 鸿蒙后台定时任务实战
  • 【win32】ffmpeg 解码器2
  • MCU知识体系
  • 【win32】ffmpeg 解码器
  • 东莞市官网网站建设公司中企动力z邮箱登录入口
  • wordpress网站seo罗夫曼三大社区模式