本文介绍23种设计模式之组合模式。
定义
允许将对象组合成树形结构来表现“整体/部分”的层次结构。组合能让用户以一致的方式来处理个别对象及对象组合。
描述
- 模式名称:COMPOSITE(组合)
- 类型:对象结构型模式
- 意图:将对象组合成树形结构以表示“部分 -整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
- 适用性:
- 想表示对象的部分-整体层次结构。
- 你希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。
- 效果:
- 优点:
- 定义了包含基本对象和组合对象的类层次结构。
- 简化客户代码。
- 使得更容易增加新类型的组件。
- 缺点:
- 很难限制组合中的组件。
类图
树形结构
组合的树形结构分为整体和部分,因此component(组件)包含了composite(组合)和leaf(叶子节点)
- Component(组件):为组合的所有对象定义一个接口,不管是组合还是叶子节点。
- Leaf(叶子节点):定义了组合中元素的行为。
- Composite(组合):定义组件的行为,这样的组件具有叶子节点。它的主要作用是存储和管理子部件,通常包含 add(Component)、remove(Component)、getChild(int) 等方法。
- 注意:所有的组件都实现了相同的接口,有些方法可能并不适合某些节点。例如 Leaf没有add,remove等操作,最好是抛出异常或者空实现。
实现代码
设计一个菜单,菜单中包含了子菜单和菜单项。
Component
public abstract class Component {
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(){
throw new UnsupportedOperationException();
}
public String getDescription(){
throw new UnsupportedOperationException();
}
public Double getPrice(){
throw new UnsupportedOperationException();
}
public void print(){
throw new UnsupportedOperationException();
}
}
Leaf
public class Leaf extends Component {
private String name;
private Double price;
private String description;
public Leaf(String name, Double price, String description) {
this.name = name;
this.price = price;
this.description = description;
}
@Override
public String getName() {
return name;
}
@Override
public Double getPrice() {
return price;
}
@Override
public String getDescription() {
return description;
}
@Override
public void print() {
System.out.println("树叶" + name + ":被访问!");
}
}
Composite
public class Composite extends Component {
private ArrayList<Component> list = new ArrayList<>();
private String name;
private String desc;
public Composite(String name, String desc) {
this.name = name;
this.desc = desc;
}
@Override
public void add(Component component) {
list.add(component);
}
@Override
public void remove(Component component) {
list.remove(component);
}
@Override
public Component getChild(int index) {
return list.get(index);
}
@Override
public String getName() {
return name;
}
@Override
public String getDescription() {
return desc;
}
@Override
public void print() {
System.out.println("树枝" + name + ":被访问!");
Iterator<Component> iterator = list.iterator();
while (iterator.hasNext()){
Component next = iterator.next();
next.print();
}
}
}
Client
public class Client {
public static void main(String[] args) {
Component component1 = new Composite("菜单1","早餐");
Component component2 = new Composite("菜单2","午餐");
Component component3 = new Composite("菜单3","晚餐");
component1.add(new Leaf("面包",1d,""));
component1.add(new Leaf("牛奶",3d,""));
component1.add(new Leaf("鸡蛋",2d,""));
Composite composite = new Composite("豪华晚餐", "");
composite.add(new Leaf("神户牛肉",3000d,""));
component3.add(composite);
Component all = new Composite("总菜单","");
all.add(component1);
all.add(component2);
all.add(component3);
all.print();
}
}
执行结果:
树枝总菜单:被访问!
树枝菜单1:被访问!
树叶面包:被访问!
树叶牛奶:被访问!
树叶鸡蛋:被访问!
树枝菜单2:被访问!
树枝菜单3:被访问!
树枝豪华晚餐:被访问!
树叶神户牛肉:被访问!