定义

组合模式(composite pattern)允许你将对象组合成树形结构来表现“整体/部分“层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。

代码实现

本章使用组合模式来实现下图的树状菜单。

首先为菜单和菜单项创建一个共同的接口作为组件接口,让我们能够用统一的做法来处理菜单和菜单项。换句话说,客户(Waitress)可以针对菜单或菜单项调用相同的方法。

组件接口MenuComponent.java

import java.util.*;
// MenuComponent对每个方法都提供了默认的实现,
// 菜单和菜单项的角色不同,所以有些方法可能并不适合某种节点。
// 面对这种情况,默认实现抛出UnsupportedOperationException,当菜单或菜单项不支持某个操作时,继承默认实现即可
public abstract class MenuComponent {// Composite应该实现的方法public void add(MenuComponent menuComponent) {throw new UnsupportedOperationException();}public void remove(MenuComponent menuComponent) {throw new UnsupportedOperationException();}public MenuComponent getChild(int i) {throw new UnsupportedOperationException();}public String getName() {throw new UnsupportedOperationException();}public String getDescription() {throw new UnsupportedOperationException();}public double getPrice() {throw new UnsupportedOperationException();}public boolean isVegetarian() {throw new UnsupportedOperationException();}// 菜单和菜单项都应该实现的方法,而且实现方式要不同public void print() {throw new UnsupportedOperationException();}
}

Leaf节点MenuItem.java

import java.util.Iterator;
import java.util.ArrayList;public class MenuItem extends MenuComponent {String name;String description;boolean vegetarian;double price;public MenuItem(String name, String description, boolean vegetarian, double price) { this.name = name;this.description = description;this.vegetarian = vegetarian;this.price = price;}public String getName() {return name;}public String getDescription() {return description;}public double getPrice() {return price;}public boolean isVegetarian() {return vegetarian;}public void print() {System.out.print("  " + getName());if (isVegetarian()) {System.out.print("(v)");}System.out.println(", " + getPrice());System.out.println("     -- " + getDescription());}
}

Composite节点Menu.java

import java.util.Iterator;
import java.util.ArrayList;public class Menu extends MenuComponent {ArrayList menuComponents = new ArrayList();String name;String description;public Menu(String name, String description) {this.name = name;this.description = description;}public void add(MenuComponent menuComponent) {menuComponents.add(menuComponent);}public void remove(MenuComponent menuComponent) {menuComponents.remove(menuComponent);}public MenuComponent getChild(int i) {return (MenuComponent)menuComponents.get(i);}public String getName() {return name;}public String getDescription() {return description;}// 对菜单的每一项进行遍历:// 使用menuComponents生成迭代器,//     通过迭代器遍历menuComponents的每一项,//     直接调用MenuItem.print或者递归调用Menu.printpublic void print() {System.out.print("\n" + getName());System.out.println(", " + getDescription());System.out.println("---------------------");Iterator iterator = menuComponents.iterator();while (iterator.hasNext()) {MenuComponent menuComponent = (MenuComponent)iterator.next();menuComponent.print();}}
}

客户Waitress的代码

import java.util.Iterator;public class Waitress {MenuComponent allMenus;public Waitress(MenuComponent allMenus) {this.allMenus = allMenus;}public void printMenu() {allMenus.print();}
}

测试驱动代码

import java.util.*;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);pancakeHouseMenu.add(new MenuItem("K&B's Pancake Breakfast", "Pancakes with scrambled eggs, and toast", true,2.99));pancakeHouseMenu.add(new MenuItem("Regular Pancake Breakfast", "Pancakes with fried eggs, sausage", false,2.99));pancakeHouseMenu.add(new MenuItem("Blueberry Pancakes","Pancakes made with fresh blueberries, and blueberry syrup",true,3.49));pancakeHouseMenu.add(new MenuItem("Waffles","Waffles, with your choice of blueberries or strawberries",true,3.59));dinerMenu.add(new MenuItem("Vegetarian BLT","(Fakin') Bacon with lettuce & tomato on whole wheat", true, 2.99));dinerMenu.add(new MenuItem("BLT","Bacon with lettuce & tomato on whole wheat", false, 2.99));dinerMenu.add(new MenuItem("Soup of the day","A bowl of the soup of the day, with a side of potato salad", false, 3.29));dinerMenu.add(new MenuItem("Hotdog","A hot dog, with saurkraut, relish, onions, topped with cheese",false, 3.05));dinerMenu.add(new MenuItem("Steamed Veggies and Brown Rice","Steamed vegetables over brown rice", true, 3.99));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));dessertMenu.add(new MenuItem("Cheesecake","Creamy New York cheesecake, with a chocolate graham crust",true,1.99));dessertMenu.add(new MenuItem("Sorbet","A scoop of raspberry and a scoop of lime",true,1.89));cafeMenu.add(new MenuItem("Veggie Burger and Air Fries","Veggie burger on a whole wheat bun, lettuce, tomato, and fries",true, 3.99));cafeMenu.add(new MenuItem("Soup of the day","A cup of the soup of the day, with a side salad",false, 3.69));cafeMenu.add(new MenuItem("Burrito","A large burrito, with whole pinto beans, salsa, guacamole",true, 4.29));Waitress waitress = new Waitress(allMenus);waitress.printMenu();}
}

该模式体现了哪些OO原则

  1. 原则2: 针对接口编程,而不是针对实现编程

    Waitress和MenuTestDrive都是针对MenuComponent的接口编程,不关心具体实现。

本章总结

  1. 组合模式以单一责任设计原则换取透明性(transparency)。透明性是指通过让组件接口Component同时包含一些管理子节点和叶节点操作,客户就可以将组合和叶节点一视同仁。也就是说,一个元素究竟是组合还是叶节点,对客户是透明的。现在MenuComponent类中同时具有两种类型的操作。因为客户有机会对一个元素做一些不恰当或者没有意义的操作(如试图把菜单添加到菜单项),所以我们失去了一些安全性。这是设计上的抉择,我们也可以采用另外一种方向的设计,将责任区分开来放在不同的接口中。这样一来,设计上就比较安全,但是我们失去了透明性,客户的代码将必须用条件语句和instanceof操作符处理不同类型的节点。这是一个典型的折衷案例。尽管我们受到设计原则的指导,但是我们总是需要观察某原则对我们的设计所造成的影响。

  2. 组合结构内任意对象称为组件,组件可以是组合,也可以是叶节点

《HeadFirst设计模式》读书笔记-第9章v2-组合模式相关推荐

  1. Head First设计模式读书笔记八 第九章下 组合模式

    之前的总结链接: https://blog.csdn.net/u011109881/article/details/58710579 对比headFirst书中的例子,我觉得书中的组合模式的例子比上面 ...

  2. Head First设计模式读书笔记八 第九章上 迭代器模式

    之前的总结: https://blog.csdn.net/u011109881/article/details/59677544 个人觉得本章节,HeadFirst讲的没有之前看到的网站讲的清晰,至少 ...

  3. HeadFirst设计模式读书笔记

    简单的做下笔记,以后找起来方便.设计原则通用,不针对哪个模式. 1 策略模式 定义了算法族,分别封装起来,让它们之间可以相互替换,此模式让算法的变化独立于使用算法的客户. 设计原则: 找出应用中可能需 ...

  4. 设计模式学习笔记(九)——Composite组合模式

    Composite组合模式主要是应对这样的问题:一类具有"容器特征"的对象--即他们在充当对象的同时,又是其他对象的容器的情况.在编写时我们常常会造成:客户代码过多地依赖于对象容器 ...

  5. 《Head First设计模式》读书笔记 -- (第一章)策略模式

    本文属贫僧不吃肉原创,欢迎转载,转载请注明来自 http://never-say-never.iteye.com/blog/851923 在开始之前,先熟悉一下OO设计的一些原则. OO设计原则之一: ...

  6. 《大话设计模式》读书笔记-第8章 工厂方法模式

    1.工厂方法(Factory Method),定义一个用于创建对象的接口,让子类决定实例化哪一个类.工厂方法是一个类的实例化延迟到其子类. 2.工厂方法(Factory Method)结构图 3.工厂 ...

  7. 《headfirst设计模式》读书笔记9-迭代器和组合模式

    目录 1. 封装遍历 2. 定义迭代器模式 2.1 部分源码 2.1.1 MenuItem.h 2.1.2 Menu.h 2.1.3 Iterator.h 2.1.4 ArrayIterator.h ...

  8. HeadFirst设计模式读书笔记--观察者模式(2)(二)

    设计气象站(案例) 实现气象站 public interface Subject{/**这两个方法都需要观察者作为变量,该观察者是用来注册或被删除的*/public void registerObse ...

  9. JavaScript模式读书笔记 第5章 对象创建模式

    1,命名空间模式  namespace   <script> var myApp = {};//通过全局变量来实现命名空间 maApp.Parent = function (){   }; ...

最新文章

  1. python字符编码讲解_python 字符编码讲解
  2. mysql基本语句集合
  3. HTTP状态码(HTTP Status Code),常见的error 404, error 504等的意思
  4. 如何获取服务器上文件的hashcode,java获取文件hashcode
  5. 自学计算机科学CS总结-by 要有光LTBL
  6. Fluid 架构创新论文被国际数据库顶会 ICDE 录用
  7. Hbase 01_初学必知
  8. HTML5移动端音乐播放器(启蒙篇)
  9. Swiftfox:极速的冲浪体验
  10. ArcGIS 的 http://localhost:8399/arcgis/rest/services 无法打开,显示404 的解决办法
  11. 让Python更加充分的使用Sqlite3
  12. REMOTE HOST IDENTIFICATION HAS CHANGED!
  13. 论软件产品的易用性(二)
  14. 适用于高密度或高精度应用的高度可配置和可扩展的螺旋电容器设计
  15. 漫谈CRM体系化建设3:如何留住客户
  16. 车辆ECU综合测试系统研究
  17. CYUSB3014 USB3.0与FPGA设计
  18. 服务器内存延迟,内存、延迟等性能全面测试
  19. Data Analysis - Day2 - Matplotlib 案例
  20. 基于PyQt5实现的PDF小工具

热门文章

  1. 数据结构之顺序表(C语言)
  2. 使用魔法电脑安装最新华为电脑管家多屏协同
  3. 设置web页面鼠标样式
  4. 2008.06.02 读华为前执行副总裁李玉琢的《我与商业领袖的合作与冲突》有感(三)
  5. java如何读写操作yaml文件展示
  6. 中国传媒大学计算机学院期末考试题,2020中国传媒大学计算机技术考研专业课大纲、真题答题方法...
  7. Opencv--20行代码实现椭圆检测
  8. 【Python】Python 入门基础
  9. Java Security
  10. Cisco命令中login和login local的区别