|
Design Pattern - Iterator
|
| (史帝芬, 2007/05/26, hi.steven@gmail.com) |
Iterator在C#、Java等語言中使用的相當普遍,使用Iterator pattern的目的
在於穩藏聚合物件的實作細節,僅提供外界一個可存取聚合物件內部元素的介面,程式只要透過Iterator
介面,即可走訪聚合物件的各個元素。
現在假設有家銀行,代理了許多債券基金,並寫了如程式1所示的程式用ArrayList 來儲存其代理的基金,測試程式顯示,當要存取這些基金時,我們需要了解ArrayList的用法,才能巡訪並存取 每支基金。
using System;
using System.Collections;
namespace Iterator
{
public class Debenture
{
private string id; //基金編號
private string name; //基金名稱
private double currentValue; //現值
private double rate; //配息率
public Debenture(string id, string name, double initialValue, double rate)
{
this.id = id;
this.name = name;
this.currentValue = initialValue;
this.rate = rate;
}
public string Id
{
get { return id; }
}
public string Name
{
get { return name; }
}
public double CurrentValue
{
get { return currentValue; }
set { currentValue = value; }
}
public double Rate
{
get { return rate; }
set { rate = value; }
}
}
public class DebentureList
{
private ArrayList debenture;
public DebentureList()
{
debenture = new ArrayList();
debenture.Add(new Debenture("1616", "聯博全球高收益債券基金AT", 12.3, 0.003));
debenture.Add(new Debenture("1313", "富蘭克林坦伯頓全球債券基金", 11.5, 0.0012));
debenture.Add(new Debenture("1258", "瑞銀新興市場債券基金", 15.9, 0));
}
public ArrayList getAllItem()
{
return debenture;
}
}
class Program
{
static void Main(string[] args)
{
DebentureList debentureList = new DebentureList();
ArrayList funds = debentureList.getAllItem();
for (int i = 0; i < funds.Count; i++)
{
Debenture item = (Debenture)funds[i];
Console.WriteLine("債券基金 -- {0} ({1}): 現值 {2} 配息率 {3}", item.Id, item.Name, item.CurrentValue, item.Rate);
}
Console.ReadLine();
}
}
}
程式2,我們使用Iterator pattern改寫了上面的程式,穩藏了ArrayList, 測試程式只要知道IList及IIterator兩個介面,即可走訪所有債券基金。以後如果程式改寫了,改 用Hashtable來儲存所有基金,我們並不需要改寫程式,仍是透過Iterator走訪所有元素。 要特別注意的是,使用Iterator Pattern存取元素時,不可預設取得之元素的順序, 因為隨著使用的資料結構的不同,內含的元素即有可能會有不同的排列順序。 ![]()
using System;
using System.Collections;
namespace Iterator
{
public interface IList
{
IIterator getIterator();
}
public interface IIterator
{
bool hasNext();
Object next();
}
#region 債券基金
public class Debenture
{
private string id; //基金編號
private string name; //基金名稱
private double currentValue; //現值
private double rate; //配息率
public Debenture(string id, string name, double initialValue, double rate)
{
this.id = id;
this.name = name;
this.currentValue = initialValue;
this.rate = rate;
}
public string Id
{
get { return id; }
}
public string Name
{
get { return name; }
}
public double CurrentValue
{
get { return currentValue; }
set { currentValue = value; }
}
public double Rate
{
get { return rate; }
set { rate = value; }
}
}
public class DebentureList : IList
{
private ArrayList debenture;
public DebentureList()
{
debenture = new ArrayList();
debenture.Add(new Debenture("1616", "聯博全球高收益債券基金AT", 12.3, 0.003));
debenture.Add(new Debenture("1313", "富蘭克林坦伯頓全球債券基金", 11.5, 0.0012));
debenture.Add(new Debenture("1258", "瑞銀新興市場債券基金", 15.9, 0));
}
public ArrayList getAllItem()
{
return debenture;
}
public IIterator getIterator()
{
return new DebentureListIterator(this);
}
}
public class DebentureListIterator : IIterator
{
private DebentureList list;
private int index;
public DebentureListIterator(DebentureList list)
{
this.list = list;
index = 0;
}
public bool hasNext()
{
return index < list.getAllItem().Count;
}
public object next()
{
return list.getAllItem()[index++];
}
}
#endregion
class Program
{
static void Main(string[] args)
{
IList debentureList = new DebentureList();
IIterator iterator = debentureList.getIterator();
while (iterator.hasNext())
{
Debenture item = (Debenture)iterator.next();
Console.WriteLine("債券基金 -- {0} ({1}): 現值 {2} 配息率 {3}", item.Id, item.Name, item.CurrentValue, item.Rate);
}
Console.ReadLine();
}
}
}
C# 2.0 微軟加入了對Iterator的支援,我們只要繼承IEnumerable介面,並 實作其中的GetEnumerator method,再配合yield return語法即可輕鬆實作出Iterator pattern, 而且繼承IEnumerable的類別,還可以用foreach巡訪所有元素,以下將使用C# 2.0的特性改寫程式1。
using System;
using System.Collections;
namespace Iterator
{
public class Debenture
{
private string id; //基金編號
private string name; //基金名稱
private double currentValue; //現值
private double rate; //配息率
public Debenture(string id, string name, double initialValue, double rate)
{
this.id = id;
this.name = name;
this.currentValue = initialValue;
this.rate = rate;
}
public string Id
{
get { return id; }
}
public string Name
{
get { return name; }
}
public double CurrentValue
{
get { return currentValue; }
set { currentValue = value; }
}
public double Rate
{
get { return rate; }
set { rate = value; }
}
}
public class DebentureList : IEnumerable
{
private ArrayList debenture;
public DebentureList()
{
debenture = new ArrayList();
debenture.Add(new Debenture("1616", "聯博全球高收益債券基金AT", 12.3, 0.003));
debenture.Add(new Debenture("1313", "富蘭克林坦伯頓全球債券基金", 11.5, 0.0012));
debenture.Add(new Debenture("1258", "瑞銀新興市場債券基金", 15.9, 0));
}
#region IEnumerable 成員
public IEnumerator GetEnumerator()
{
for (int i = 0; i < debenture.Count; i++)
{
yield return debenture[i];
}
}
#endregion
}
class Program
{
static void Main(string[] args)
{
IEnumerable debentureList = new DebentureList();
foreach (Debenture item in debentureList)
{
Console.WriteLine("債券基金 -- {0} ({1}): 現值 {2} 配息率 {3}", item.Id, item.Name, item.CurrentValue, item.Rate);
}
Console.ReadLine();
}
}
}
|