【设计模式】之组合模式(Composite)
组合模式的官方定义是:把对象组合成一个树形结构来表示局部-整体的结构。组合模式让客户端可以统一地处理单独对象与对象组合。
英文定义如下:
Compose objects into tree structures to representpart-whole hierarchies. Composite lets clients treat individual objects and compositions of objectsuniformly.
定义中有三个比较重要的关键词(红色粗提部分):
第一个是tree structures,组合模式给我的感觉其实就是一颗树,能够使用到组合模式的问题,其数据结构都能抽象成一颗树,如果对于数据结构理解比较好的话,本章应该是比较简单的。
第二个是part-whole,看到part-whole,我一下联想到了本科学习图形学的时候接触到一点分形图形学的知识,因此这个理解起来也很简单,也就是局部自相似性。
第三个是uniformly,正式因为组合模式的结构是一个具有局部字相似性的数形结构,因此就可以统一地处理单个对象(类似与树中的叶子节点)与对象组合(类似与树中的父节点)。
实现组合模式的一个关键点就是,定义了一个即可以表示单个简单节点,又可以表示节点容器的基类。
The key to the composite pattern is an abstract class that represents both primitives and containers.
这样基类的必然会定义一些冗余操作,并且会带来不安全操作的副作用,所以违反了OO设计的一个原则:一个类只能定义对子类有意义的操作。
A class should only define operations that are meaningful to its subclasses.
当然这是进行OO设计不可避免的trade-off,鱼和熊掌不可兼得,关键取决于我们更需要什么,因为组合模型的一个特点就是uniformly,所以transparency比safety重要。
组合模式的使用范围是非常广泛的,最简单的例子就是MVC模型中的View,就用到了组合模式。
下面以代码为例,说明组合模式的实现方法。
首先定义一个组合模式中用到的那个比较重要的基类
public class MenuTestDrive { public static void main(String[] args) { MenuComponent pancakeHouseMenu = new Menu("PANCAKE HOUSE MENU", "Breakfast"); MenuComponent dinerMenu = new Menu("DINER MENU", "Lunch"); MenuComponent cafeMenu = new Menu("CAFE MENU", "Dinner"); MenuComponent dessertMenu = new Menu("DESSERT MENU", "Dessert of course!"); MenuComponent allMenus = new Menu("ALL MENUS", "All menus combined"); allMenus.add(pancakeHouseMenu); allMenus.add(dinerMenu); allMenus.add(cafeMenu); // add menu items here dinerMenu.add(new MenuItem( "Pasta", "Spaghetti with Marinara Sauce, and a slice of sourdough bread", true, 3.89)); dinerMenu.add(dessertMenu); dessertMenu.add(new MenuItem( "Apple Pie", "Apple pie with a flakey crust, topped with vanilla icecream", true, 1.59)); // add more menu items here Waitress waitress = new Waitress(allMenus); waitress.printMenu(); }}