迭代器模式
设计模式这一章的内容很长,其中迭代器模式很常用,而组合模式却很少碰到,首先是迭代器模式,经常在 java 集合类中使用迭代器,但是却不知道这是一种设计模式,也没有去关注底层实现,看完书本之后,有种原来是这一的感觉。
迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。
迭代器模式可以很好的隐藏内部的数据结构,让用户在遍历集合的时候与内部数据结构解藕。同时也可以以统一的方式去访问不同集合中的元素,比如数组通过下标直接获取,List通过 get 方法获取,如果使用迭代器,就可以都使用 next 方法获取了。迭代器的实现非常简单,直接代码实现一个吧。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
/**
* 迭代模式接口
*/
public interface Iterator {
/**
* 判断是否还有下一个元素
* @return
*/
boolean hasNext();
/**
* 返回下一个元素
* @return
*/
Object next();
}
/**
* 迭代器实现类,不同集合对象需要实现自己的迭代器
*/
public class CollectionIterator implements Iterator {
/**
* 记录下一个元素的位置
*/
private int index = 0;
/**
* 要迭代的集合
*/
private Object[] objects;
public CollectionIterator(Object[] objects){
this.objects = objects;
}
@Override
public boolean hasNext() {
if(index >= objects.length || objects[index] == null){
return false;
}
return true;
}
@Override
public Object next() {
Object object = objects[index];
index = index + 1;
return object;
}
}
/**
* 集合对象
*/
public class Collection {
/**
* 集合内部数据结构,比如数组,List,Set等
*/
private Object[] objects = new Object[16];
/**
* 创建迭代器,这样外部就可以以统一的方式遍历元素,而不用暴露内部的实现
* @return
*/
public Iterator createIterator(){
return new CollectionIterator(objects);
}
public void add(Object object){
// 添加元素
}
public Object get(int i){
//获取元素
return objects[i];
}
}
以上就是一个非常简单的迭代器了,在实际开发中,我们可以直接使用 java.util
中的 Iterator
接口,而不需要自己定义,java也提供了 for ( : )
方式去隐式调用迭代器。
组合模式
组合模式允许你将对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。
组合模式这个不是很好理解,通常就是以树形方式创建对象的结构,树里面包含了组合对象以及个别的对象。这个组合对象和个别对象实现了同样的接口,组合对象可以具有个别对象的子节点。个人理解就是这种结构存储有层级关系的数据,比如菜单,菜单下有子菜单,子菜单下还有子子菜单,这个结构在后台管理系统中还挺常见的,比如部门,成本中心等等。通过组合模式,操作树中的对象时,就不用去判断它到底是叶子还是层级节点,可以使用统一的方法,因为它们实现了一样的接口。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import java.util.List;
/**
* 组合接口,规范组合/个体的操作方式
* 默认 throw 异常,因为每个方法对组合/个体的意义是不一样的
*/
public abstract class MenuComponent {
/**
* 组合方法
*/
public void add(MenuComponent component){
throw new UnsupportedOperationException();
}
/**
* 组合/个体方法
* @return
*/
public void printName(){
throw new UnsupportedOperationException();
}
/**
* 组合方法
* @return
*/
public List<MenuComponent> getChild() {
throw new UnsupportedOperationException();
}
}
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* 组合对象,重写组合的所有方法
*/
public class Menu extends MenuComponent {
private String name;
/**
* 组合对象还会具有自己的子代
*/
private List<MenuComponent> child = new ArrayList<>();
public Menu(String name){
this.name = name;
}
@Override
public void add(MenuComponent component) {
this.child.add(component);
}
/**
* 打印自身,以及利用迭代器和递归打印后代
*/
@Override
public void printName() {
System.out.println(name);
Iterator iterator = child.iterator();
while (iterator.hasNext()){
MenuComponent component = (MenuComponent) iterator.next();
component.printName();
}
}
@Override
public List<MenuComponent> getChild() {
return child;
}
}
/**
* 个体对象
*/
public class MenuItem extends MenuComponent {
private String name;
public MenuItem(String name){
this.name = name;
}
/**
* 只重写个体的方法,打印自身
* @return
*/
@Override
public void printName() {
System.out.println(name);
}
}
public class SysMenuBar extends MenuComponent{
public static void main(String[] args) {
// 构造一个层级菜单
MenuComponent rootMenu = new Menu("root");
rootMenu.add(new MenuItem("root-a"));
rootMenu.add(new MenuItem("root-b"));
rootMenu.add(new MenuItem("root-c"));
MenuComponent menu_d = new Menu("root-d");
menu_d.add(new MenuItem("root-d-a"));
menu_d.add(new MenuItem("root-d-b"));
menu_d.add(new MenuItem("root-d-c"));
rootMenu.add(menu_d);
// 通过调用根节点的方法,实现遍历所有后代的方法
rootMenu.printName();
}
}
可以看出利用组合和迭代器,可以很方便的遍历树中的所有元素,对组合和个体的操作方法是一样的,这样就不用在 printName 时判断它到底是组合还是个体了。
看完整章,感觉迭代器很好理解,组合模式要深度应用还没什么想法,不过后续在代码中看到类似的场景就可以有个概念了,可以尝试去设计更好扩展的代码。