老板让我打印各个项目的报表,包括项目名称,人数,开销等信息,这个好办,看下面的类图:
image.png
然后是上面类图的代码实现,非常简单:
public interface IProject {
String getProjectInfo();
}
public class Project implements IProject {
private String name; // 项目名称
private int num; // 项目人数
private int cost; // 项目支出
public Project(String name, int num, int cost) {
this.name = name;
this.num = num;
this.cost = cost;
}
@Override
public String getProjectInfo() {
StringBuilder builder = new StringBuilder();
builder.append("项目名称:").append(name).append(",项目人数:").append(num).append(",项目支出:").append(cost);
return builder.toString();
}
}
Boss想查看各项目明细,需要这么做:
public class Boss {
public static void main(String[] args) {
// 定义一个List,存放所有的项目对象
ArrayList<IProject> projectList = new ArrayList<IProject>();
// 增加星球大战项目
projectList.add(new Project("星球大战", 10, 100000));
// 增加扭转时空项目
projectList.add(new Project("扭转时空", 100, 1000000));
// 增加超人改造项目
projectList.add(new Project("超人改造", 10000, 10000000));
// 增加100个其他项目
for (int i = 4; i < 104; i++) {
projectList.add(new Project("第" + i + "个项目", i * 5, i * 1000000));
}
// 遍历ArrayList,把所有项目的信息都取出
for (IProject project : projectList) {
System.out.println(project.getProjectInfo());
}
}
}
# 运行结果
项目名称:星球大战,项目人数:10,项目支出:100000
项目名称:扭转时空,项目人数:100,项目支出:1000000
项目名称:超人改造,项目人数:10000,项目支出:10000000
项目名称:第4个项目,项目人数:20,项目支出:4000000
......
我开始思考,在这种场景下,使用迭代器模式会更好,于是我修改了类图:
然后根据类图修改了代码:
public interface IProject {
// 增加项目
void add(String name, int num, int cost);
// 获得项目信息
String getProjectInfo();
// 获得一个可以被遍历的对象
IProjectIterator iterator();
}
public class Project implements IProject {
private List<IProject> projectList = new ArrayList<>(); // 项目列表
private String name; // 项目名称
private int num; // 项目人数
private int cost; // 项目支出
public Project() {}
private Project(String name, int num, int cost) {
this.name = name;
this.num = num;
this.cost = cost;
}
@Override
public void add(String name, int num, int cost) {
this.projectList.add(new Project(name, num, cost));
}
@Override
public String getProjectInfo() {
StringBuilder builder = new StringBuilder();
builder.append("项目名称:").append(name).append(",项目人数:").append(num).append(",项目支出:").append(cost);
return builder.toString();
}
@Override
public IProjectIterator iterator() {
return new ProjectIterator(projectList);
}
}
public interface IProjectIterator extends Iterator<IProject> {
}
大家可能很奇怪,你定义的这个接口方法、变量都没有,有什么意义呢?有意义,所有的Java书上都一直说是面向接口编程,你的接口是对一个事物的描述,也就是说我通过接口就知道这个事物有哪些方法,哪些属性,我们这里的IProjectIterator是要建立一个指向Project类的迭代器,目前暂时定义的就是一个通用的迭代器,可能以后会增加IProjectIterator的一些属性或者方法。当然了,你也可以在实现类上实现两个接口,一个是Iterator,一个是IProjectIterator(这时候,这个接口就不用继承Iterator),我的习惯是:如果我要实现一个容器或者其他API提供接口时,我一般都自己先写一个接口继承,然后再继承自己写的接口,保证自己的实现类只用实现自己写的接口(接口传递,当然也要实现顶层的接口),程序阅读也清晰一些,我们继续看迭代器的实现类:
public class ProjectIterator implements IProjectIterator {
// 项目列表
private List<IProject> projectList = new ArrayList<>();
private int currentItem = 0;
public ProjectIterator(List<IProject> projectList) {
this.projectList = projectList;
}
// 判断是否还有元素
@Override
public boolean hasNext() {
return !(currentItem >= projectList.size() || projectList.get(currentItem) == null);
}
// 取下一个值
@Override
public IProject next() {
return projectList.get(currentItem++);
}
}
然后看看Boss类有多少改动:
public class Boss {
public static void main(String[] args) {
IProject project = new Project();
// 增加星球大战项目
project.add("星球大战", 10, 100000);
// 增加扭转时空项目
project.add("扭转时空", 100, 1000000);
// 增加超人改造项目
project.add("超人改造", 10000, 10000000);
// 增加100个其他项目
for (int i = 4; i < 104; i++) {
project.add("第" + i + "个项目", i * 5, i * 1000000);
}
IProjectIterator iterator = project.iterator();
while(iterator.hasNext()) {
IProject p = iterator.next();
System.out.println(p.getProjectInfo());
}
}
}
上面的程序增加了复杂性,但是从面向对象的开发上来看,project.add()增加一个项目会更友好一些,上面的例子就使用了迭代器模式。
现在迭代器模式有点没落了,从JDK1.2版本开始增加java.util.Iterator这个接口,并逐步把Iterator应用到各个集合类中,大部分集合类都有iterator()这个方法,我们可以通过这个方法去遍历集合类中的所有方法或属性,不需要自己再去写迭代器,所以基本上很少有项目再独立写迭代器了,直接使用List或者Map就可以完整的解决问题。
本文原书: 《您的设计模式》 作者:CBF4LIFE