如何能够以一个统一的方式来访问内部实现不同的聚合对象?
迭代器模式的定义:
提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示
所谓聚合对象是一组对象的组合结构,比如:Java中的集合,数组
Iterator:迭代器接口,定义访问和遍历元素的接口
ConcreteIterator:具体的迭代器对象。实现对聚合对象的遍历,并跟踪遍历时的当前位置
Aggregate:聚合对象,定义创建相应迭代器对象的接口
ConcreteAggregate:具体聚合对象,实现创建相应的迭代器对象
代码:
/**
* 迭代器接口,定义访问和遍历元素的操作
*/
public interface Iterator {
/**
* 移动到聚合对象的第一个位置
*/
public void first();
/**
* 移动到聚合对象的下一个位置
*/
public void next();
/**
* 判断是否已经移动聚合对象的最后一个位置
* @return true表示已经移动聚合对象的最后一个位置,
* false表示还没有移动到聚合对象的最后一个位置
*/
public boolean isDone();
/**
* 获取迭代的当前元素
* @return 迭代的当前元素
*/
public Object currentItem();
}
/**
* 用来实现访问数组的迭代接口
*/
public class ArrayIteratorImpl implements Iterator{
/**
* 用来存放被迭代的聚合对象
*/
private SalaryManager aggregate = null;
/**
* 用来记录当前迭代到的位置索引
* -1表示刚开始的时候,迭代器指向聚合对象第一个对象之前
*/
private int index = -1;
public ArrayIteratorImpl(SalaryManager aggregate){
this.aggregate = aggregate;
}
public void first(){
index = 0;
}
public void next(){
if(index < this.aggregate.size()){
index = index + 1;
}
}
public boolean isDone(){
if(index == this.aggregate.size()){
return true;
}
return false;
}
public Object currentItem(){
return this.aggregate.get(index);
}
}
/**
* 用来实现访问Collection集合的迭代接口,为了外部统一访问方式
*/
public class CollectionIteratorImpl implements Iterator{
/**
* 用来存放被迭代的聚合对象
*/
private PayManager aggregate = null;
/**
* 用来记录当前迭代到的位置索引
* -1表示刚开始的时候,迭代器指向聚合对象第一个对象之前
*/
private int index = -1;
public CollectionIteratorImpl(PayManager aggregate){
this.aggregate = aggregate;
}
public void first(){
index = 0;
}
public void next(){
if(index < this.aggregate.size()){
index = index + 1;
}
}
public boolean isDone(){
if(index == this.aggregate.size()){
return true;
}
return false;
}
public Object currentItem(){
return this.aggregate.get(index);
}
}
/**
* 聚合对象的接口,定义创建相应迭代器对象的接口
*/
public abstract class Aggregate {
/**
* 工厂方法,创建相应迭代器对象的接口
* @return 相应迭代器对象的接口
*/
public abstract Iterator createIterator();
}
/**
* 客户方已有的工资管理对象
*/
public class PayManager extends Aggregate{
/**
* 聚合对象,这里是Java的集合对象
*/
private List list = new ArrayList();
/**
* 获取工资列表
* @return 工资列表
*/
public List getPayList(){
return list;
}
/**
* 计算工资,其实应该有很多参数,为了演示从简
*/
public void calcPay(){
//计算工资,并把工资信息填充到工资列表里面
//为了测试,做点假数据进去
PayModel pm1 = new PayModel();
pm1.setPay(3800);
pm1.setUserName("张三");
PayModel pm2 = new PayModel();
pm2.setPay(5800);
pm2.setUserName("李四");
list.add(pm1);
list.add(pm2);
}
public Iterator createIterator(){
return new CollectionIteratorImpl(this);
}
public Object get(int index){
Object retObj = null;
if(index < this.list.size()){
retObj = this.list.get(index);
}
return retObj;
}
public int size(){
return this.list.size();
}
}
/**
* 被客户方收购的那个公司的工资管理类
*/
public class SalaryManager extends Aggregate{
/**
* 用数组管理
*/
private PayModel[] pms = null;
/**
* 获取工资列表
* @return 工资列表
*/
public PayModel[] getPays(){
return pms;
}
/**
* 计算工资,其实应该有很多参数,为了演示从简
*/
public void calcSalary(){
//计算工资,并把工资信息填充到工资列表里面
//为了测试,做点假数据进去
PayModel pm1 = new PayModel();
pm1.setPay(2200);
pm1.setUserName("王五");
PayModel pm2 = new PayModel();
pm2.setPay(3600);
pm2.setUserName("赵六");
pms = new PayModel[2];
pms[0] = pm1;
pms[1] = pm2;
}
public Iterator createIterator(){
return new ArrayIteratorImpl(this);
}
public Object get(int index){
Object retObj = null;
if(index < pms.length){
retObj = pms[index];
}
return retObj;
}
public int size(){
return this.pms.length;
}
}
/**
* 工资描述模型对象
*/
public class PayModel {
/**
* 支付工资的人员
*/
private String userName;
/**
* 支付的工资数额
*/
private double pay;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public double getPay() {
return pay;
}
public void setPay(double pay) {
this.pay = pay;
}
public String toString(){
return "userName="+userName+",pay="+pay;
}
}
public class Client {
public static void main(String[] args) {
//访问集团的工资列表
PayManager payManager= new PayManager();
//先计算再获取
payManager.calcPay();
System.out.println("集团工资列表:");
test(payManager.createIterator());
//访问新收购公司的工资列表
SalaryManager salaryManager = new SalaryManager();
//先计算再获取
salaryManager.calcSalary();
System.out.println("新收购的公司工资列表:");
test(salaryManager.createIterator());
}
/**
* 测试通过访问聚合对象的迭代器,是否能正常访问聚合对象
* @param it 聚合对象的迭代器
*/
private static void test(Iterator it){
//循环输出聚合对象中的值
//首先设置迭代器到第一个元素
it.first();
while(!it.isDone()){
//取出当前的元素来
Object obj = it.currentItem();
System.out.println("the obj=="+obj);
//如果还没有迭代到最后,那么就向下迭代一个
it.next();
}
}
}
3. 研磨设计模式
1) 迭代器模式的关键思想是把对聚合对象的遍历和访问从聚合对象中分离出来,放入单独的迭代器中。
2)Java中的迭代器:java.util.Iterator
3)具有迭代策略的迭代器
4)双向迭代器:java.util.ListIterator
/**
* 迭代器接口,定义访问和遍历元素的操作,实现双向迭代
*/
public interface Iterator {
/**
* 移动到聚合对象的第一个位置
*/
public void first();
/**
* 移动到聚合对象的下一个位置
*/
public void next();
/**
* 判断是否已经移动聚合对象的最后一个位置
* @return true表示已经移动聚合对象的最后一个位置,
* false表示还没有移动到聚合对象的最后一个位置
*/
public boolean isDone();
/**
* 获取迭代的当前元素
* @return 迭代的当前元素
*/
public Object currentItem();
/**
* 判断是否为第一个元素
* @return 如果为第一个元素,返回true,否则返回false
*/
public boolean isFirst();
/**
* 移动到聚合对象的上一个位置
*/
public void previous();
}
5)迭代器的本质是:控制访问聚合对象中的元素
6)翻页迭代:
public class PayModel {
private String userName;
private double pay;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public double getPay() {
return pay;
}
public void setPay(double pay) {
this.pay = pay;
}
public String toString(){
return "userName="+userName+",pay="+pay;
}
}
/**
* 定义翻页访问聚合元素的迭代接口
*/
public interface AggregationIterator {
/**
* 判断是否还有下一个元素,无所谓是否够一页的数据,
* 因为最后哪怕只有一条数据,也是要算一页的
* @return 如果有下一个元素,返回true,没有下一个元素就返回false
*/
public boolean hasNext();
/**
* 取出下面几个元素
* @param num 需要获取的记录条数
* @return 下面几个元素
*/
public Collection next(int num);
/**
* 判断是否还有上一个元素,无所谓是否够一页的数据,
* 因为最后哪怕只有一条数据,也是要算一页的
* @return 如果有上一个元素,返回true,没有上一个元素就返回false
*/
public boolean hasPrevious();
/**
* 取出上面几个元素
* @param num 需要获取的记录条数
* @return 上面几个元素
*/
public Collection previous(int num);
}
/**
* 被客户方收购的那个公司的工资管理类
*/
public class SalaryManager{
/**
* 用数组管理
*/
private PayModel[] pms = null;
/**
* 获取工资列表
* @return 工资列表
*/
public PayModel[] getPays(){
return pms;
}
/**
* 计算工资,其实应该有很多参数,为了演示从简
*/
public void calcSalary(){
//计算工资,并把工资信息填充到工资列表里面
//为了测试,做点假数据进去
PayModel pm1 = new PayModel();
pm1.setPay(2200);
pm1.setUserName("王五");
PayModel pm2 = new PayModel();
pm2.setPay(3600);
pm2.setUserName("赵六");
PayModel pm3 = new PayModel();
pm3.setPay(2200);
pm3.setUserName("王五二号");
PayModel pm4 = new PayModel();
pm4.setPay(3600);
pm4.setUserName("赵六二号");
PayModel pm5 = new PayModel();
pm5.setPay(2200);
pm5.setUserName("王五三号");
pms = new PayModel[5];
pms[0] = pm1;
pms[1] = pm2;
pms[2] = pm3;
pms[3] = pm4;
pms[4] = pm5;
}
public AggregationIterator createIterator() {
return new ArrayIteratorImpl(this);
}
}
/**
* 用来实现翻页访问聚合元素的迭代接口
*/
public class ArrayIteratorImpl implements AggregationIterator{
/**
* 用来存放被迭代的数组
*/
private PayModel[] pms = null;
/**
* 用来记录当前迭代到的位置索引
*/
private int index = 0;
public ArrayIteratorImpl(SalaryManager aggregate){
this.pms = aggregate.getPays();
}
public boolean hasNext() {
//判断是否还有下一个元素
if(pms!=null && index<=(pms.length-1)){
return true;
}
return false;
}
public Collection next(int num) {
Collection col = new ArrayList();
int count=0;
while(hasNext() && count 0){
return true;
}
return false;
}
public Collection previous(int num){
Collection col = new ArrayList();
int count=0;
//简单的实现就是把索引退回去num个,然后再取值。
//但事实上这种实现是有可能多退回去数据的,
//比如:已经到了最后一页,而且最后一页的数据不够一页的数据,那么退回去num个索引就退多了
//为了示例的简洁性,这里就不去处理了
index = index - num;
while(hasPrevious() && count