本文出自 http://blog.csdn.net/shuangde800
认识组合模式
上一篇中,我们可以用迭代器来实现遍历一个集合(数组,ArrayList, Vector, HashTable等)。
假设有这样一种集合结构:餐厅里有一份菜单,菜单里面还有子菜单,其实就是一个树形的结构
那么,之前的迭代器就不能用了。
我们需要新的设计:
1. 需要某种树形结构,可以容纳菜单,子菜单和菜单项
2. 需要确定能够在每个菜单的各个项之间游走,而且至少要像现在用迭代器一样方便
3. 我们也需要更有弹性地在菜单之间游走。比方说,可能只需要遍历甜点菜单,或者可以遍历餐厅的整个菜单
定义组合模式
组合模式允许你将对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及对象组合
有时候又叫做部分-整体模式,它使我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以向处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。
组合模式让你可以优化处理递归或分级数据结构。有许多关于分级数据结构的例子,使得组合模式非常有用武之地。关于分级数据结构的一个普遍性的例子是你每次使用电脑时所遇到的:文件系统。文件系统由目录和文件组成。每个目录都可以装内容。目录的内容可以是文件,也可以是目录。按照这种方式,计算机的文件系统就是以递归结构来组织的。如果你想要描述这样的数据结构,那么你可以使用组合模式Composite。
以嵌套菜单为例,这个模式能够创建一个树形结构,在同一个结构中处理嵌套菜单和菜单项组。通过将菜单和项放在相同的结构中,我们创建了一个“整体/部分”层次结构,即由菜单和菜单项组成的对象树。但是可以将它视为一个整体,像是一个丰富的大菜单。
一旦有了丰富的“大菜单”,我们就可以用这个模式来“统一处理个别对象和组合对象”。
这意味着,如果我们有了一个树形结构的菜单,子菜单和可能还带有菜单项的子菜单,那么任何一个菜单都是一种“组合”。因为它既可以包含其他菜单,也可以包含菜单项。我们可以忽略对象组合和个别对象之间的差别。
使用组合模式,只要写出简单的代码,就能够对整个菜单结构应用相同的操作!
利用组合设计菜单
1. 实现菜单组件
// 菜单组件的抽象类
// 菜单组件的角色是为叶子节点和组合节点提供一个共同的接口
// 所有的组件都必须实现MenuComponent接口
// 但是叶节点和在组合节点的角色不同,所以有些方法可能不适合某些节点
// 面对这种情况,最好抛出运行时异常
public abstract class MenuComponent {
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();
}
}
2. 实现菜单项
// 这是组合类图的叶类,这里是菜单项
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;
}
// 这里和之前的实现不一样
// 我们覆盖了print()方法
// 对菜单项来说,此方法会打印出完整的菜单条目
// 包括名字,描述,价格等
public void print() {
System.out.print(" " + getName());
if (isVegetarian()) {
System.out.print("(v)");
}
System.out.println(", " + getPrice());
System.out.println(" -- " + getDescription());
}
}
3. 实现组合菜单
public class Menu extends MenuComponent {
// 菜单可以有任意数目的儿子
// 且这些儿子必须属于MenuComonent类型
// 在内部ArrayList里记录它们
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;
}
// 递归打印菜单
public 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();
}
}
}
组合迭代器
组合模式的迭代器需要用递归来实现
public class CompositeIterator implements Iterator {
Stack stack = new Stack();
// 将我们需要遍历的顶层组合的迭代器传入
// 放进一个栈数据结构中
public CompositeIterator(Iterator iterator) {
stack.push(iterator);
}
// 当客户想要取得下一个元素的时候
// 我们先调用hashNext()来判断是否还有下一个元素
public Object next() {
if (hasNext()) {
Iterator iterator = (Iterator) stack.peek();
MenuComponent component = (MenuComponent) iterator.next();
if (component instanceof Menu) {
// 如果元素是菜单,我们有了另一个需要被包含进遍历中的组合
// 将它放进栈中
stack.push(component.createIterator());
}
return component;
} else {
return null;
}
}
public boolean hasNext() {
if (stack.empty()) { //如果栈空了,说明没有下一个元素了
return false;
} else {
Iterator iterator = (Iterator) stack.peek();
if (!iterator.hasNext()) {
stack.pop();
return hasNext();
} else {
return true;
}
}
}
// 不支持删除
public void remove() {
throw new UnsupportedOperationException();
}
}
空迭代器
先要一个组合迭代器,那么每个组件都要加上createIterator()方法。
在菜单中实现:
public class Menu extends MenuComponent {
// 其它部分代码不需要修改
public Iterator createIterator() {
return new CompositeIterator(menuComponents.iterator()) ;
}
}
但是在菜单项中要怎样实现呢?我们知道菜单项是叶子节点,没有什么可以遍历了。
有两种选择:
选择一: 返回null
我们可以让createItrerator()方法返回null,但是如果这样做,我们的客户代码就要条件语句来判断返回值是否为null
选择二:返回一个迭代器,这个迭代器的hasNext()永远返回false
这个方法显然更好,客户就不必担心是否为null了。
public class NullIterator implements Iterator {
public Object next() {
return null;
}
public boolean hasNext() {
return false;
}
public void remove() {
throw new UnsupportedOperationException();
}
}
菜单项实现createIterator()方法
public class MenuItem extends MenuComponent {
// 其它部分代码不需要修改
public Iterator createIterator() {
return new NullIterator(); // 返回空迭代器
}
}
分享到:
相关推荐
以上就是压缩包中的设计模式学习笔记涉及到的主要内容。通过对这些模式的理解和应用,开发者可以更好地解决软件设计中的问题,提升软件的质量和可维护性。每种模式都有其适用场景,理解其背后的意图和应用场景是关键...
这里我们聚焦于C#语言中的设计模式学习笔记,涵盖了多种经典的设计模式,如合成模式、桥梁模式、装饰模式、享元模式、门面模式、命令模式、工厂方法、策略模式、代理模式以及状态模式。下面将对这些模式逐一进行详细...
设计模式的学习不仅帮助我们编写更可维护、可扩展的代码,还能提高团队间的沟通效率,因为它们提供了通用的语言和解决方案。在实际开发中,灵活运用这些设计模式可以有效解决设计问题,提升代码质量。因此,深入理解...
"GoF 23种设计模式学习笔记" 是一个深入探讨这23个经典设计模式的资源,这些模式最初由Erich Gamma、Richard Helm、Ralph Johnson和John Vlissides四位作者在1994年的著作《设计模式:可复用面向对象软件的基础》中...
在《Head First 设计模式学习笔记(十四)模式的组合使用》中,作者探讨了如何在实际编程中灵活地组合多种设计模式以解决复杂问题。这篇文章可能是基于《Head First 设计模式》这本书的一个章节,该书是设计模式领域...
以下是一些在尚学堂300Java设计模式部分学习笔记中涉及的设计模式的知识点: 创建型模式: 创建型模式主要解决对象创建的问题,确保系统的灵活性和封装创建细节。学习笔记中提到了5种创建型模式: 1. 单例模式...
### 23种设计模式学习笔记 #### 一、软件设计模式的概念与意义 **概念:** 软件设计模式(Software Design Pattern),又称设计模式,是一套被广泛采用、经过整理和分类的代码设计经验总结。它针对软件设计过程中...
### 设计模式学习笔记 #### 引言 设计模式(Design Patterns)是在软件设计领域内广泛应用的一种实践指南,它提供了一系列解决常见问题的方案。设计模式可以被理解为面向对象软件设计的经验总结,是对特定面向对象...
学习设计模式对于软件开发人员来说至关重要,主要基于以下几点理由: - **经验借鉴**:设计模式是基于众多专家的经验和智慧,提供了经过实践检验的解决方案。 - **提高可维护性和可复用性**:通过遵循已知的最佳...
本笔记主要涵盖了多种经典的设计模式,以下是对这些模式的详细解释: 1. 单例模式(Singleton):确保一个类只有一个实例,并提供全局访问点。在Java中,通常通过双重检查锁定(Double-Check Locking)或静态内部类...
文档中描述的是Java设计模式学习笔记,目前涉及了7种设计模式,但没有具体指明这7种模式是什么,计划后续增加更多的模式。虽然文件内容中存在OCR扫描的识别错误,但不影响我们从整体上把握设计模式的脉络和学习方法...
设计模式是软件工程中的一种重要概念,它代表了在特定情境下解决常见问题的最佳实践。...通过“23种设计模式的解析与C++实现.pdf”和“Source”文件,读者可以深入学习并实践这些模式,提升自己的编程技能。
根据提供的文件信息,我们可以将设计模式分为两大类:创建型模式和结构型模式,并在此基础上进一步探讨每种设计模式的特点及应用场景。 ### 创建型模式 #### Singleton(单例)模式 - **定义**:确保一个类仅有一...
在《23个设计模式图解--学习笔记》中,我们探讨了这些模式,以便于理解和应用到实际开发中。以下是这23个设计模式的详细说明: 1. **工厂方法**(Factory Method):定义一个用于创建对象的接口,让子类决定实例化...
文档中的“23种设计模式学习笔记.doc”可能包含了对这23种模式的详细解释和实例,而“设计模式之我爱我家.doc”可能从一个更生活化的角度来阐述设计模式的概念。“软件23种设计模式,超级经典的.pdf”可能是对这些...
通过阅读这份笔记,读者不仅可以学习到设计模式的基本概念,还能了解到如何在Java环境中实际运用这些模式,提升编程技能。设计模式的学习和掌握是成为一名优秀程序员的必经之路,它们能帮助我们写出更高效、更灵活、...
### 设计模式笔记 #### 一、引言 设计模式是一种在特定情境下解决软件设计问题的标准化解决方案。它是从无数编程实践中提炼出来的精华,帮助开发者更好地理解和应对复杂的问题。在学习设计模式的过程中,我们通常...
本资料“图解Java设计模式笔记总结word版本”聚焦于通过图文并茂的方式,深入浅出地解析各种设计模式。以下是基于这个主题的详细知识点讲解: 1. **设计模式的分类** - **创建型模式**:如单例(Singleton)、工厂...
总之,“设计模式的读书总结笔记”是一份宝贵的资源,它可以帮助开发者系统地学习和掌握设计模式,提升软件设计的质量和效率。无论是初学者还是经验丰富的开发者,都可以从中受益匪浅。通过深入学习和实践,我们可以...