写在模式学习之前
什么是设计模式:在我们进行程序设计时,逐渐形成了一些典型问题和问题的解决方案,这就是软件模式;每一个模式描述了一个在我们程序设计中经常发生的问题,以及该问题的解决方案;当我们碰到模式所描述的问题,就可以直接用相应的解决方法去解决这个问题,这就是设计模式。
设计模式就是抽象出来的东西,它不是学出来的,是用出来的;或许你根本不知道任何模式,不考虑任何模式,却写着最优秀的代码,即使以“模式专家”的角度来看,都是最佳的设计,不得不说是“最佳的模式实践”,这是因为你积累了很多的实践经验,知道“在什么场合代码应该怎么写”,这本身就是设计模式。
有人说:“水平没到,学也白学,水平到了,无师自通”。诚然,模式背熟,依然可能写不出好代码,更别说设计出好框架;OOP理解及实践经验到达一定水平,同时也意味着总结了很多好的设计经验,但"无师自通",却也未必尽然,或者可以说,恰恰是在水平和经验的基础上,到了该系统的学习一下“模式”的时候了,学习一下专家总结的结果,印证一下自己的不足,对于提高水平还是很有帮助的。
本系列的设计模式学习笔记,实际是对于《Java与模式》这本书的学习记录。
迭代模式的定义
首先要说,关于迭代模式,是和Java中的聚集密切相关的。体现的是“开-闭”原则,强调的是封装变化的思想。
迭代器是在JDK2-5时代的聚集遍历模式,从JKD5开始,对聚集的遍历,推崇for(E e:Es)的形式,更少的变量,更不易出错,当然其核心还是迭代器,会被编译器编译成Iterator,我们学习迭代模式,主要是为了开阔一下视野,理解其思想。
迭代模式是为了解决两类问题:
1、迭代逻辑没有改变,但是需要从一种聚集变成另一种聚集,如果不同的聚集有不同的遍历接口方式,那么客户端就需要修改代码了,所以。。。
2、迭代逻辑改变了,比如只需要遍历>1的元素,这个时候就需要修改聚集中原来的遍历方法,或者提供新的方法,这不符合“开-闭”原则,也就是没有“把不变的结构(聚集)从系统中抽象出来,把可变的结构(各种条件的遍历)封装起来”,对于这种思想,Java是这样实现的,伪代码如下:
public class Aggregation
{
public Iterator<E> iterator() {
return new Itr();
}
public ListIterator<E> listIterator() {
return new ListItr(0);
}
//迭代子类
private class Itr implements java.util.Iterator<E>
{
...
}
//迭代子类
private class ListItr implements java.util.ListIterator<E>
{
...
}
}
迭代模式的定义:
迭代模式,又叫游标模式,是对象的行为模式。迭代模式可以顺序的访问一个聚集中的元素而不必暴漏聚集的内部对象。
迭代模式的结构
结构图
所涉及的角色
(1)抽象迭代(Iterator)角色:定义遍历元素所需的接口
(2)具体迭代(ConcreteIterator)角色:实现了Iterator接口,并保持迭代过程中的游标位置
(3)聚集(Aggregate)角色:这个角色会给出创建迭代对象的接口
(4)具体聚集(ConcreteAggregate)角色:实现了创建迭代对象的接口,并返回一个合适的具体迭代对象
(5)客户端(Client)角色:持有对聚集及其迭代对象的引用,调用迭代对象的迭代接口,也有可能通过迭代对象操作聚集元素的增加和删除
代码实现
import java.util.Vector;
public class IteratorTest {
public static void main(String[] args)
{
System.out.println("正向迭代演示");
Purchase a = new PurchaseOfCopyA();
a.add("one");a.add("tow");a.add("three");
Iterator ia = a.createIterator();
ia.first();
while(!ia.isLast())
{
System.out.println("a: " + ia.current());
ia.next();
}
System.out.println("逆向迭代演示");
Purchase b = new PurchaseOfCopyB();
b.add("one");b.add("tow");b.add("three");
Iterator ib = b.createIterator();
ib.first();
while(!ib.isLast())
{
System.out.println("b: " + ib.current());
ib.next();
}
}
}
/**
* 抽象聚集类
*
*/
@SuppressWarnings(value={"rawtypes","unchecked"})
abstract class Purchase
{
private Vector elements = new Vector(5);
//工厂方法模式,提供迭代对象的实现
public abstract Iterator createIterator();
public void add(Object o)
{
elements.add(o);
}
public void remove(Object o)
{
elements.remove(o);
}
public Object currentItem(int index)
{
return elements.elementAt(index);
}
public int count()
{
return elements.size();
}
}
/**
* 具体聚集类:警察A
*
*/
class PurchaseOfCopyA extends Purchase
{
@Override
public Iterator createIterator() {
return new ForwardIterator(this);
}
}
/**
* 具体聚集类:警察B
*
*/
class PurchaseOfCopyB extends Purchase
{
@Override
public Iterator createIterator() {
return new BackIterator(this);
}
}
/**
* 抽象迭代角色
*
*/
interface Iterator
{
void first(); //移到第一个元素
void next(); //移到下一个元素
boolean isLast(); //是否最后一个元素
Object current(); //当前的元素
}
/**
* 正向迭代
*
*/
class ForwardIterator implements Iterator
{
private int index;
private Purchase obj;
public ForwardIterator(Purchase obj)
{
this.obj = obj;
}
@Override
public void first() {
index = 0;
}
@Override
public void next() {
if(!isLast())
{
index++;
}
}
@Override
public boolean isLast() {
if(index > obj.count()-1) return true;
return false;
}
@Override
public Object current() {
return obj.currentItem(index);
}
}
/**
* 逆向迭代
*
*/
class BackIterator implements Iterator
{
private int index;
private Purchase obj;
public BackIterator(Purchase obj)
{
this.obj = obj;
}
@Override
public void first() {
index = obj.count()-1;
}
@Override
public void next() {
if(!isLast())
{
index--;
}
}
@Override
public boolean isLast() {
if(index < 0) return true;
return false;
}
@Override
public Object current() {
return obj.currentItem(index);
}
}
迭代模式优缺点
优点:
(1)符合“开-闭”原则,封装变化,不论是聚集对象变化,或者迭代规则变化,都不会影响到客户端的代码;
(2)每个聚集对象可以有一个以上的迭代对象,彼此独立。因此一个聚集可以同时有几个迭代在进行之中;
缺点:
(1)迭代必须以一定线性顺序进行,聚集并不一定是线性的,比如Hash,所以使用迭代可能导致客户端误会,误认为聚集是线性的;
(2)迭代给出的聚集元素没有类型特征,一般都是Object,因此需要客户端具备这些元素类型的知识。