在Java项目里,组合模式和外观模式都属于结构型设计模式,但解决的问题并不相同。组合模式关注对象结构的统一处理,外观模式关注子系统调用的简化。理解它们的实现方式有助于写出更易维护的代码。
什么是组合模式
组合模式将对象组合成树形结构,使得用户对单个对象和组合对象的访问具有一致性。核心是用一个抽象组件定义公共方法,叶子节点和容器节点都实现它。
组合模式示例代码
下面用一个文件系统的例子说明组合模式的基本实现:
// 抽象组件
abstract class FileSystemNode {
protected String name;
public FileSystemNode(String name) {
this.name = name;
}
public abstract void print(String indent);
}
// 叶子节点
class File extends FileSystemNode {
public File(String name) {
super(name);
}
public void print(String indent) {
System.out.println(indent + "文件: " + name);
}
}
// 组合节点
class Directory extends FileSystemNode {
private java.util.List<FileSystemNode> children = new java.util.ArrayList<>();
public Directory(String name) {
super(name);
}
public void add(FileSystemNode node) {
children.add(node);
}
public void print(String indent) {
System.out.println(indent + "目录: " + name);
for (FileSystemNode node : children) {
node.print(indent + " ");
}
}
}
public class CompositeDemo {
public static void main(String[] args) {
Directory root = new Directory("root");
root.add(new File("a.txt"));
Directory sub = new Directory("sub");
sub.add(new File("b.txt"));
root.add(sub);
root.print("");
}
}
什么是外观模式
外观模式为一组复杂的子系统接口提供一个统一的高层接口,客户端只需要和外观类交互,不需要了解子系统内部的细节。它降低了系统的耦合度。
外观模式示例代码
假设有一个家庭影院系统,包含投影仪、音响和播放器:
class Projector {
public void on() { System.out.println("投影仪打开"); }
public void off() { System.out.println("投影仪关闭"); }
}
class SoundSystem {
public void on() { System.out.println("音响打开"); }
public void setVolume(int v) { System.out.println("音量: " + v); }
}
class Player {
public void play(String movie) { System.out.println("播放: " + movie); }
}
// 外观类
class HomeTheaterFacade {
private Projector projector;
private SoundSystem sound;
private Player player;
public HomeTheaterFacade() {
projector = new Projector();
sound = new SoundSystem();
player = new Player();
}
public void watchMovie(String movie) {
projector.on();
sound.on();
sound.setVolume(10);
player.play(movie);
}
public void stopMovie() {
projector.off();
}
}
public class FacadeDemo {
public static void main(String[] args) {
HomeTheaterFacade facade = new HomeTheaterFacade();
facade.watchMovie("测试影片");
facade.stopMovie();
}
}
两者对比与应用建议
从结构上看,组合模式强调部分与整体的层次关系,外观模式强调对外接口的封装。实际项目中可参考下表选择:
| 模式 | 适用场景 | 主要目的 |
|---|---|---|
| 组合模式 | 菜单、目录、组织架构等树形数据 | 统一处理单个与组合对象 |
| 外观模式 | 多模块子系统调用、第三方库封装 | 简化调用、降低耦合 |
小结
在Java开发里,如果业务数据天然具备层次结构,优先考虑组合模式;如果需要屏蔽底层复杂度、给上层提供简单入口,则使用外观模式。二者也可配合使用,例如在外观类内部用组合模式管理多个子服务。