文档章节

HeadFirst设计模式(十一) - 组合模式

XuePeng77
 XuePeng77
发布于 2016/08/15 22:19
字数 1311
阅读 43
收藏 0

餐厅需求

    给予之前的迭代模式,餐厅的菜单管理系统需要有煎饼屋菜单和披萨菜单。现在希望在披萨菜单中能够加上一份餐后甜点的子菜单。

    在迭代模式中,披萨菜单是用数组维护的,我们需要让披萨菜单持有一份子菜单,但是不能真的把他赋值给菜单项数组,因为类型不同,所以不能这么做。

    所以,需要重新实现煎饼屋菜单和披萨菜单了。事实是,我们已经到达了一个复杂级别,如果现在不重新设计,就无法容纳未来增加的菜单或子菜单的需求。我们需要一下改变:

  • 需要某种树形结构,可以容纳菜单、子菜单和菜单项;
  • 需要确定能够在每个菜单的各个项之间游走,而且至少像用迭代器一样方便;
  • 需要能够更有弹性地在菜单项之间游走。比方说,可能只需要遍历甜点菜单,或者可以便利整个菜单;

    我们要使用组合模式来解决这个问题,但并没有放弃迭代器模式,它仍然是解决方案中的一部分,然而管理菜单的问题已经到了一个迭代器无法解决的新维度。所以,我们将倒退几步,使用组合模式来解决。

    组合模式让我们能用树形方式创建对象的结构,树里面包含了组合以及个别的对象。使用组合结构,我们能把相同的操作应用在组合的个别对象上,换句话说,在大多数情况下,我们可以忽略对象组合和个别对象之间的差别。

组合模式的类图

    我们要如何将组合模式利用在菜单上呢?一开始,我们需要创建一个组件接口来作为菜单和菜单项的共同接口,让我们能够用同意的做法来处理菜单和菜单项。来看看设计的类图:

    菜单组件MenuComponent提供了一个接口,让菜单项和菜单共同使用。因为我们希望能够为这些方法提供默认的实现,所以我们在这里可以把MenuComponent接口换成一个抽象类。在这个类中,有显示菜单信息的方法getName()等,还有操纵组件的方法add(),remove(),getChild()等。

    菜单项MenuItem覆盖了显示菜单信息的方法,而菜单Menu覆盖了一些对他有意义的方法。

    具体来看看代码实现:

package cn.net.bysoft.composite;

public abstract class MenuComponent {
	
	// add,remove,getchild
	// 把组合方法组织在一起,即新增、删除和取得菜单组件
	
	public void add(MenuComponent component) {
		throw new UnsupportedOperationException();
	}
	
	public void remove(MenuComponent component) {
		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();
	}
}
package cn.net.bysoft.composite;

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 boolean isVegetarian() {
		return vegetarian;
	}

	public double getPrice() {
		return price;
	}

	public void print() {
		System.out.println(" " + getName());
		if (isVegetarian()) {
			System.out.println("(V)");
		}
		System.out.println(", " + getPrice());
		System.out.println(" -- " + getDescription());
	}
}
package cn.net.bysoft.composite;

import java.util.ArrayList;
import java.util.Iterator;

public class Menu extends MenuComponent {
	ArrayList<MenuComponent> menuComponents = new ArrayList<MenuComponent>();
	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 menuComponents.get(i);
	}
	
	public String getName() {
		return name;
	}
	
	public String getDescription() {
		return description;
	}
	
	public void print() {
		System.out.println("\n" + getName());
		System.out.println(", " + getDescription());
		System.out.println("----------------------");
		
		Iterator<MenuComponent> iterator = menuComponents.iterator();
		while(iterator.hasNext()) {
			MenuComponent menuComponent = iterator.next();
			menuComponent.print();
		}
	}
}
package cn.net.bysoft.composite;

public class Waitress {
	MenuComponent allMenus;

	public Waitress(MenuComponent allMenus) {
		this.allMenus = allMenus;
	}

	public void printMenu() {
		allMenus.print();
	}
}
package cn.net.bysoft.composite;

public class Client {

	public static void main(String[] args) {
		// 创建菜单对象
		MenuComponent pancakeHouseMenu = new Menu("煎饼屋菜单", "提供各种煎饼。");
		MenuComponent pizzaHouseMenu = new Menu("披萨屋菜单", "提供各种披萨。");
		MenuComponent cafeMenu = new Menu("咖啡屋菜单", "提供各种咖啡");
		// 创建一个顶层的菜单
		MenuComponent allMenus = new Menu("All Menus", "All menus combined");
		// 把所有菜单都添加到顶层菜单
		allMenus.add(pancakeHouseMenu);
		allMenus.add(pizzaHouseMenu);
		allMenus.add(cafeMenu);
		// 在这里加入菜单项
		pancakeHouseMenu.add(new MenuItem("苹果煎饼", "香甜苹果煎饼", true, 5.99));
		pizzaHouseMenu.add(new MenuItem("至尊披萨", "意大利至尊咖啡", false, 12.89));
		cafeMenu.add(new MenuItem("美式咖啡", "香浓美式咖啡", true, 3.89));
		
		Waitress waitress = new Waitress(allMenus);
		waitress.printMenu();
	}

}

    组合博士以单一责任设计原则换取透明性。通过让组件的接口同时包含一些管理子节点和叶节点的操作,客户就可以将组合和叶节点一视同仁。也就是说,一个元素究竟是组合还是叶节点,对客户是透明的。

    现在,我们在MenuComponent类中同时具有两种类型的操作。因为客户有机会对一个元素做一些不恰当或是没有意义的操作,所以我们失去了一些安全性。
    以上便是组合模式的一些内容。

© 著作权归作者所有

共有 人打赏支持
XuePeng77
粉丝 42
博文 135
码字总数 178151
作品 0
丰台
私信 提问
(目录)设计模式(可复用面向对象软件的基础)

本系列“设计模式”博客使用Golang语言实现算法。所谓算法是指解决一个问题的步骤,个人觉得不在于语言。小弟只是最近学习Golang,所以顺带熟练一下语法知识,别无它意。 本系列博客主要介绍...

chapin
2015/01/13
0
0
【设计模式笔记】(十六)- 代理模式

一、简述 代理模式(Proxy Pattern),为其他对象提供一个代理,并由代理对象控制原有对象的引用;也称为委托模式。 其实代理模式无论是在日常开发还是设计模式中,基本随处可见,中介者模式中...

MrTrying
06/24
0
0
小菜学设计模式——设计模式总结之创建型

1、面向过程与面向对象 1)面向过程通过划分功能模块,通过函数间相互调用来实现,但需求变化时就需要更改函数,而你改动的函数有多少地方在调用她呢?关联多少数据,这是很不容易弄得清楚地...

learn_more
2015/07/05
0
0
小菜学设计模式——设计模式总结之结构型

1、设计模式总结 设计模式总共23个,但是常用的不到10个,下面就把这23个设计模式进行整理归类,具体如下: 1)创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型...

learn_more
2015/07/06
0
0
设计模式 2014-12-19

book: 阎宏《JAVA与模式》 架构设计栏目 http://blog.csdn.net/enterprise/column.html 概要: http://bbs.csdn.net/forums/Embeddeddriver 23种设计模式分别是: 1.单例模式 2.工厂方法模式...

jayronwang
2014/12/19
0
0

没有更多内容

加载失败,请刷新页面

加载更多

新技术不断涌现,下一代云计算的突破口在哪里?

这是一个IT技术飞速发展的时代,在硬件基础设施的不断升级以及虚拟化网络等技术的日益成熟下,云厂商也正面临着各种新技术带来的巨大挑战。从数据中心的基础建设到云平台的系统构建再到产品底...

UCloudTech
6分钟前
0
0
走进阿里云物联网

课程介绍: 阿里云IoT,致力于实现万物互联的美好世界,为生态合作伙伴提供基于云边端一体化、人工智能、安全的物联网基础平台和内容服务能力平台,通过该平台高效连接、管理设备的同时,开放...

mcy0425
13分钟前
0
0
Kylin2.5.0环境搭建及操作记录

Apache Kylin是一个开源的分布式分析引擎,提供Hadoop/Spark之上的SQL查询接口及多维分析(OLAP)能力以支持超大规模数据,最初由eBay Inc. 开发并贡献至开源社区。它能在亚秒内查询巨大的H...

PeakFang-BOK
22分钟前
1
0
SpringBoot整合es

文档对像 @Document(indexName = "bigdata",type = "tag")public class User { @Idprivate String openid; private List<String> tags;public String getOpenid() ......

魔法王者安琪拉
26分钟前
1
0
windows下让 jar 在后台运行的办法

windows下 运行 java jar 不出现 命令行 窗口 新建一个披处理 run.bat,内容如下 @echo off start javaw -jar xx.jar exit 双击运行即可。...

glen_xu
35分钟前
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部