设计模式-组合模式详解
组合模式详解
目录
- 组合模式简介
- 核心流程
- 重难点分析
- Spring中的源码分析
- 具体使用场景
- 面试高频点
组合模式简介
定义
组合模式(Composite Pattern)是一种结构型设计模式,它将对象组合成树形结构以表示"部分-整体"的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
核心思想
- 统一接口:叶子节点和组合节点使用相同的接口
- 递归结构:支持树形结构的递归操作
- 透明性:客户端无需区分叶子节点和组合节点
- 整体-部分:将部分对象组合成整体对象
模式结构
- Component(抽象构件):为组合中的对象声明接口,在适当情况下实现所有类共有接口的默认行为
- Leaf(叶子构件):在组合中表示叶子节点对象,叶子节点没有子节点
- Composite(组合构件):定义有子部件的那些部件的行为,存储子部件,在Component接口中实现与子部件有关的操作
核心流程
组合模式流程图
基本实现流程
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();}
}
面试高频点
面试知识点思维导图
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. 与其他模式的对比
问题:组合模式与装饰器模式的区别?
答案要点:
- 目的:组合模式是结构组合,装饰器模式是功能增强
- 关系:组合模式是部分-整体关系,装饰器模式是包装关系
- 结构:组合模式是树形结构,装饰器模式是链式结构
- 使用场景:组合模式用于层次结构,装饰器模式用于功能扩展
问题:组合模式与迭代器模式的关系?
答案要点:
- 组合关系:组合模式经常与迭代器模式结合使用
- 遍历需求:组合结构需要遍历所有节点
- 实现方式:可以使用迭代器模式遍历组合结构
- 性能优化:迭代器模式可以优化组合结构的遍历性能
总结
组合模式是一种重要的结构型设计模式,它通过将对象组合成树形结构,实现了部分-整体的层次结构,并提供了统一的接口。
核心优势
- 统一接口:叶子节点和组合节点使用相同接口
- 递归结构:支持树形结构的递归操作
- 透明性:客户端无需区分叶子节点和组合节点
- 扩展性:易于添加新的叶子节点和组合节点
注意事项
- 性能考虑:深层递归可能影响性能
- 内存管理:复杂结构需要注意内存泄漏
- 设计复杂度:增加了系统的复杂度
- 类型安全:透明式模式可能产生运行时异常
在实际开发中,组合模式特别适用于需要表示部分-整体层次结构的场景,如文件系统、组织架构、菜单系统等。通过合理使用组合模式,可以大大提高系统的灵活性和可维护性。