1. 程式人生 > >研磨設計模式之迭代器業務場景

研磨設計模式之迭代器業務場景

場景描述

專案客戶方收購了一家小公司,這家小公司有自己的工資系統,客戶方的工資系統內部採用List來記錄工資列表,新收購的小公司的工資系統內部採用陣列來記錄工資列表,整合兩個系統的工資表資料

已有系統程式碼示例

  • 一個統一了的工資描述模型
/**
 * 
 * 工資描述模型物件
 */
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; } @Override public String toString
() { return "userName="+userName+",pay="+pay; } }
  • 客戶方已有的工資管理系統中的工資管理類,內部使用List來管理
/**
 * 客戶方已有的工資管理物件 
 *
 */
public class PayManager {
    /**
     * 聚合物件,使用List管理
     */
    private List<PayModel> list = new ArrayList<>();
    /**
     * 獲取工資列表
     * @return 工資列表
     */
public List<PayModel> getPayList() { return list; } /** * 計算工資 */ public void calcPay() { //計算工資,把工資資訊填充到工資列表中 PayModel pm1 = new PayModel(); pm1.setUserName("張三"); pm1.setPay(3000); PayModel pm2 = new PayModel(); pm2.setUserName("李四"); pm2.setPay(5000); list.add(pm1); list.add(pm2); } }
  • 被收購公司的工資系統中的工資管理類,內部通過陣列來管理
/**
 * 
 * 被客戶方收購的公司的工資管理類
 *
 */
public class SalaryManager {
    /**
     * 使用陣列管理
     */
    private PayModel[] pms = null;

    /**
     * 獲取工資列表
     * 
     * @return 工資列表
     */
    public PayModel[] getPays() {
        return pms;
    }
    /**
     * 計算工資
     */
    public void calcSalary() {
        PayModel pm1 = new PayModel();
        pm1.setUserName("王五");
        pm1.setPay(3300);
        PayModel pm2 = new PayModel();
        pm2.setUserName("趙六");
        pm2.setPay(4100);
        pms = new PayModel[2];
        pms[0] = pm1;
        pms[1] = pm2;
    }
}
  • 此時來訪問兩個系統的工資列表,外部要採用不同的訪問方式,一個是訪問陣列,一個是訪問集合物件
PayManager payManager = new PayManager();
payManager.calcPay();
Iterator<PayModel> it = payManager.getPayList().iterator();
System.out.println("集團工資列表");
while(it.hasNext()) {
    PayModel m = it.next();
    System.out.println(m);
}

SalaryManager sm = new SalaryManager();
sm.calcSalary();
PayModel[] pms = sm.getPays();
System.out.println("新收購公司工資列表");
for(int i=0;i<pms.length;i++) {
    System.out.println(pms[i]);
}
  • 為了能讓客戶端以一個統一的方式進行訪問,最容易的方式就是為它們定義一個統一的介面
/**
 * 迭代器介面,定義訪問和遍歷元素的操作
 *
 */
public interface Iterator {

    /**
     * 移動到聚合物件的第一個位置
     */
    public void first();
    /**
     * 移動到聚合物件的下一個位置
     */
    public void next();

    /**
     * 判斷是否已經移動到聚合物件的最後一個位置
     * @return true表示已經移動到聚合物件的最後一個位置
     *         false 表示還沒有移動到聚合物件的最後一個位置
     */
    public boolean isDone();
    /**
     * 獲取迭代的當前元素
     * @return 迭代的當前元素
     */
    public Object currentItem();
}
  • 定義統一介面來獲取聚合物件
/**
 * 聚合物件的介面,定義建立相應迭代器物件介面
 *
 */
public abstract class Aggregate {

    /**
     * 工廠方法,建立相應迭代器物件的介面
     * @return 相應迭代器物件的介面
     */
    public abstract Iterator createIterator();
}
  • 定義好了統一的介面,就需要分別實現這個介面,一個採用陣列實現
/**
 * 
 *  用來實現訪問陣列的迭代介面
 */
public class ArrayIteratorImpl implements Iterator{

    /**
     * 用來存放被迭代的聚合物件
     */
    private SalaryManager aggregate = null;
    /**
     * 用來記錄當前被迭代到的位置索引
     * -1 表示剛開始的時候,迭代器指向聚合物件第一個元素之前
     */
    private int index = -1;

    public ArrayIteratorImpl(SalaryManager aggregate) {
        this.aggregate = aggregate;
    }

    @Override
    public void first() {

        index = 0;
    }

    @Override
    public void next() {
        if(index<this.aggregate.size()) {
            index = index + 1;
        }
    }

    @Override
    public boolean isDone() {
        if(index == this.aggregate.size()) {
            return true;
        }
        return false;
    }

    @Override
    public Object currentItem() {
        return this.aggregate.get(index);
    }

}
  • 用List實現的統一介面
/**
 * 用來實現訪問Collection集合的迭代幾口,為了外部統一訪問方式 
 *
 */
public class CollectionIteratorImpl implements Iterator{

    /**
     * 用來存放被迭代的物件
     */
    private PayManager aggregate = null;

    private int index = -1;

    public CollectionIteratorImpl(PayManager aggregate) {
        this.aggregate = aggregate;
    }


    @Override
    public void first() {
        index = 0;
    }

    @Override
    public void next() {
        if(index < this.aggregate.size()) {
            index = index + 1;
        }
    }

    @Override
    public boolean isDone() {
        if(index == this.aggregate.size()) {
            return true;
        }
        return false;
    }

    @Override
    public Object currentItem() {
        return this.aggregate.get(index);
    }

}
  • 讓PayManager和SalaryManager繼承Aggregate,提供分別訪問它們的訪問聚合的介面
/**
 * 客戶方已有的工資管理物件 
 *
 */
public class PayManager extends Aggregate{

    @Override
    public Iterator createIterator() {
        return new CollectionIteratorImpl(this);
    }

    public PayModel get(int index) {
        PayModel ret = null;
        if(index<this.list.size()) {
            ret = this.list.get(index);
        }
        return ret;
    }

    public int size() {
        return this.list.size();
    }
    /**
     * 聚合物件,使用List管理
     */
    private List<PayModel> list = new ArrayList<>();
    /**
     * 獲取工資列表
     * @return 工資列表
     */
    public List<PayModel> getPayList() {
        return list;
    }
    /**
     * 計算工資
     */
    public void calcPay() {
        //計算工資,把工資資訊填充到工資列表中
        PayModel pm1 = new PayModel();
        pm1.setUserName("張三");
        pm1.setPay(3000);
        PayModel pm2 = new PayModel();
        pm2.setUserName("李四");
        pm2.setPay(5000);
        list.add(pm1);
        list.add(pm2);
    }

}
/**
 * 
 * 被客戶方收購的公司的工資管理類
 *
 */
public class SalaryManager extends Aggregate{


    @Override
    public Iterator createIterator() {
        return new ArrayIteratorImpl(this);
    }

    public PayModel get(int index) {
        PayModel ret = null;
        if(index < this.pms.length) {
            ret = pms[index];
        }
        return ret;
    }
    public int size() {
        return this.pms.length;
    }


    /**
     * 使用陣列管理
     */
    private PayModel[] pms = null;

    /**
     * 獲取工資列表
     * 
     * @return 工資列表
     */
    public PayModel[] getPays() {
        return pms;
    }
    /**
     * 計算工資
     */
    public void calcSalary() {
        PayModel pm1 = new PayModel();
        pm1.setUserName("王五");
        pm1.setPay(3300);
        PayModel pm2 = new PayModel();
        pm2.setUserName("趙六");
        pm2.setPay(4100);
        pms = new PayModel[2];
        pms[0] = pm1;
        pms[1] = pm2;
    }

}
  • 把通過訪問聚合介面來訪問聚合物件的功能獨立成一個方法,雖然是不同的聚合物件,但是都呼叫這個方法去訪問
public static void test(Iterator it) {
    it.first();
    while(!it.isDone()) {
        Object obj = it.currentItem();
        System.out.println(obj);
        it.next();
    }
}
  • 客戶端呼叫
PayManager payManager = new PayManager();
payManager.calcPay();
System.out.println("集團工資列表");
test(payManager.createIterator());
SalaryManager sm = new SalaryManager();
sm.calcSalary();
System.out.println("新收購公司工資列表");
test(sm.createIterator());

如同上面的程式碼示例,提供一個統一訪問聚合物件的介面,通過這個介面就能順序的訪問聚合物件的元素,對於客戶端而言,只是面向這個介面在訪問,根本不需要知道聚合物件內部的表示方法