設計模式學習筆記之迭代器模式

birdlove1987發表於2017-03-12

什麼是迭代器模式呢?

迭代器模式就是提供一種方法順序訪問一個聚合物件中的各種元素,而又不暴露該物件的內部表示。

理解起來是不是很抽象?我們下面馬上舉個例子!

很多玩LOL的玩家可能都知道,LOL在中國的聯賽LPL聯賽。



嗯,這個比賽的參賽俱樂部的管理組織就是大名鼎鼎的中國電子競技俱樂部聯盟(Association of China E-sports)簡稱ACE聯盟。該組織負責國內職業電子競技戰隊註冊、管理、轉會、賽事監督等多方面工作,並頒佈職業聯賽參賽俱樂部管理辦法、職業選手個人行為規範等多個條例。

下面我們來建立一個LPL聯絡的兩支參賽隊在ACE的管理和介紹系統。這兩支隊伍分別是IG戰隊和WE戰隊。

我們先來構建一個參賽隊員類:


//遊戲選手類
public class GamePlayer 
{
	//姓名和選手描述
	private String name,description;
	//是否為男性選手
	private boolean male;
	//身價
	private float salary;
	
	//初始化建構函式
	public GamePlayer(String name,String description,boolean male,float salary)
	{
		this.name=name;
		this.description=description;
		this.male=male;
		this.salary=salary;
	}
	
	public String getName()
	{
		return name;
	}
	public String getDescription()
	{
		return description;
	}
	public float getSalary()
	{
		return salary;
	}
	public boolean isMale()
	{
		return male;
	}
}


再來構建IG戰隊類


public class IgLolGameTeam 
{
	//最大上場隊員數
	private final static int Max_Players=5;
	//隊員統計
	public int numberOfplayer=0;
	//隊員儲存陣列
	private GamePlayer[] gameplayers;
	//建構函式
	public IgLolGameTeam()
	{
		gameplayers=new GamePlayer[Max_Players] ;
		addPlayer("上單_957","A級",true,900000f);
		addPlayer("打野_Condi","A級",true,800000f);
		addPlayer("中單_xiye","S級",true,1500000f);
		addPlayer("AD_MyStic","S級",true,130000f);
		addPlayer("輔助_Zero","A級",true,800000f);
	}
	
	//新增隊員函式
	private void addPlayer(String name, String description, boolean male,float salary) 
	{
		GamePlayer gameplayer = new GamePlayer(name, description, male, salary);
		if(numberOfplayer>=Max_Players)
		{
			System.err.println("sorry,menu is full!can not add another item");
		}else{
			gameplayers[numberOfplayer]=gameplayer;
			numberOfplayer++;
		}
	}
	
	//獲取所有上場隊員
	public GamePlayer[] getGamePlayers() 
	{
		return gameplayers;
	}
}


WE戰隊類


public class WeLolGameTeam 
{
	//隊員儲存陣列
	private ArrayList<GamePlayer> gameplayers;
	//建構函式
	public WeLolGameTeam() 
	{
		gameplayers = new ArrayList<GamePlayer>();
		addPlayer("上單_Duke","S級",true,2000000f);
		addPlayer("打野_Kid","A級",true,1000000f);
		addPlayer("中單_Rookie","S級",true,1500000f);
		addPlayer("AD_Rain","A級",true,90000f);
		addPlayer("輔助_Tabe","A級",true,900000f);
	}
	
	//新增隊員函式
	private void addPlayer(String name, String description, boolean male,float salary) 
	{
		GamePlayer gameplayer = new GamePlayer(name, description, male, salary);
		gameplayers.add(gameplayer);
	}
	
	//獲取所有上場隊員
	public ArrayList<GamePlayer> getGamePlayers() 
	{
		return gameplayers;
	}

}


我們可以看到,由於每個戰隊的管理風格不同,所以各戰隊間的儲存隊員的資料結構也各不相同,WE用的是動態陣列,而IG戰隊使用的就是一般的陣列。


下面我們來構建ACE聯盟類:


public class  AssociationOfChinaEsports 
{
	//戰隊
	private IgLolGameTeam mIgLolGameTeam;
	private WeLolGameTeam mWeLolGameTeam;
	//隊員儲存
	private ArrayList<GamePlayer> gameplayers_we;
	private GamePlayer[] gameplayers_ig;
	
	//建構函式
	public AssociationOfChinaEsports() 
	{
		//戰隊初始化
		mWeLolGameTeam = new WeLolGameTeam();
		gameplayers_we = mWeLolGameTeam.getGamePlayers();

		mIgLolGameTeam = new IgLolGameTeam();
		gameplayers_ig = mIgLolGameTeam.getGamePlayers();
	}
	
	//列印隊員資訊
	public void printPlayer()
	{
		GamePlayer gameplayer;
		System.out.println("IG戰隊隊員:");
		for (int i = 0, len = gameplayers_we.size(); i < len; i++) 
		{
			gameplayer = gameplayers_we.get(i);
			System.out.println(gameplayer.getName() + "***" +gameplayer.isMale() + "***" + gameplayer.getDescription());
		}
		
		System.out.println("=========================================");
		
		System.out.println("WE戰隊隊員:");
		for (int i = 0, len = mIgLolGameTeam.numberOfplayer; i < len; i++)
		{
			gameplayer = gameplayers_ig[i];
			System.out.println(gameplayer.getName() + "***" +gameplayer.isMale() + "***" + gameplayer.getDescription());
		}
	}
}

下面我們用測試函式輸出一下,我們每個隊員的資訊


public class MainTest 
{
	public static void main(String[] args) 
	{
		
		AssociationOfChinaEsports mAssociationOfChinaEsports=new AssociationOfChinaEsports();
		
		mAssociationOfChinaEsports.printPlayer();
	}
}




在這個例子中我們可能會發現一些問題:由於各個戰隊之間的管理不同(儲存),導致在ACE裡不能進行統一的處理,這樣會過多的暴露各個戰隊的機密資訊,比如各個選手的工資水平,而這些資訊對於每個戰隊來講都是絕密的。

那我們應該怎麼辦呢?這裡就應該使用迭代器模式去處理這個問題了。

首先,我們先定義一個迭代器介面


//迭代器介面
public interface Iterator {
	//判斷是否有下一個隊員
	public boolean hasNext();
	//返回下一個隊員
	public Object next();
}


然後重新構建兩個戰隊的類,並用內部類的形式實現迭代器

IG:


public class IgLolGameTeam 
{
	//最大上場隊員數
	private final static int Max_Players=5;
	//隊員統計
	public int numberOfplayer=0;
	//隊員儲存陣列
	private GamePlayer[] gameplayers;
	//建構函式
	public IgLolGameTeam()
	{
		gameplayers=new GamePlayer[Max_Players] ;
		addPlayer("上單_957","A級",true,900000f);
		addPlayer("打野_Condi","A級",true,800000f);
		addPlayer("中單_xiye","S級",true,1500000f);
		addPlayer("AD_MyStic","S級",true,130000f);
		addPlayer("輔助_Zero","A級",true,800000f);
	}
	
	//新增隊員函式
	private void addPlayer(String name, String description, boolean male,float salary) 
	{
		GamePlayer gameplayer = new GamePlayer(name, description, male, salary);
		if(numberOfplayer>=Max_Players)
		{
			System.err.println("sorry,menu is full!can not add another item");
		}else{
			gameplayers[numberOfplayer]=gameplayer;
			numberOfplayer++;
		}
	}
	
	//獲取迭代器
	public Iterator getIterator()
	{
		return new IgLolGameTeamIterator() ;
	}
	
	//實現迭代器
	class IgLolGameTeamIterator implements Iterator 
	{
		private int position;

		public IgLolGameTeamIterator() 
		{
			position = 0;
		}

		@Override
		public boolean hasNext() 
		{
			// TODO Auto-generated method stub
			if (position < numberOfplayer) {
				return true;
			}
			return false;
		}

		@Override
		public Object next() 
		{
			// TODO Auto-generated method stub
			GamePlayer gameplayer_sub = gameplayers[position];
			position++;
			return gameplayer_sub;
		}
	};
}

WE


public class WeLolGameTeam 
{
	//隊員儲存陣列
	private ArrayList<GamePlayer> gameplayers;
	//建構函式
	public WeLolGameTeam() 
	{
		gameplayers = new ArrayList<GamePlayer>();
		addPlayer("上單_Duke","S級",true,2000000f);
		addPlayer("打野_Kid","A級",true,1000000f);
		addPlayer("中單_Rookie","S級",true,1500000f);
		addPlayer("AD_Rain","A級",true,90000f);
		addPlayer("輔助_Tabe","A級",true,900000f);
	}
	
	//新增隊員函式
	private void addPlayer(String name, String description, boolean male,float salary) 
	{
		GamePlayer gameplayer = new GamePlayer(name, description, male, salary);
		gameplayers.add(gameplayer);
	}
	
	//獲取迭代器
	public Iterator getIterator() 
	{
		return new WeLolGameTeamIterator();
	}
	
	//實現迭代器
	class WeLolGameTeamIterator implements  Iterator
	{		
		private int position=0;
		public WeLolGameTeamIterator()
		{
			  position=0;
		}
		
		 	@Override
			public boolean hasNext() 
		 	{
			// TODO Auto-generated method stub
			if(position<gameplayers.size())
			{
				return true;
			}
			
			return false;
		}

		@Override
		public Object next() 
		{
			// TODO Auto-generated method stub
			GamePlayer gameplayer_sub =gameplayers.get(position);
			position++;
			return gameplayer_sub;
		}};
}


然後是ACE聯盟來處理這些迭代器


public class  AssociationOfChinaEsports 
{
	private ArrayList<Iterator> iterators=new ArrayList<Iterator>();
	
	public AssociationOfChinaEsports() 
	{
		
	}
	
	//新增迭代器
	public void addIterator(Iterator iterator)
	{
		iterators.add(iterator);
	}
	
	//列印隊員資訊
	public void printMenu() 
	{
		Iterator iterator;
		GamePlayer menuItem;
		for (int i = 0, len = iterators.size(); i < len; i++) 
		{
			iterator = iterators.get(i);
			System.out.println("戰隊介紹:");
			while(iterator.hasNext())
			{
				menuItem=(GamePlayer) iterator.next();
				System.out.println(menuItem.getName() + "***" +menuItem.isMale()+"***" + menuItem.getDescription());	
			}
			System.out.println("=============================================");
		}
	}
}

最後我們來測試一下


public class MainTest 
{
	public static void main(String[] args) 
	{
		AssociationOfChinaEsports mAssociationOfChinaEsports=new AssociationOfChinaEsports();
		IgLolGameTeam mIgLolGameTeam = new IgLolGameTeam();
		WeLolGameTeam mWeLolGameTeam = new WeLolGameTeam();
		
		mAssociationOfChinaEsports.addIterator(mIgLolGameTeam.getIterator());
		mAssociationOfChinaEsports.addIterator(mWeLolGameTeam.getIterator());
		mAssociationOfChinaEsports.printMenu();
	}
}



這回我們可以清晰的看見,在ACE聯盟類中,每個戰隊都沒有暴露他們的細節,這就是迭代器模式的有點


迭代器模式的優點有:
1.簡化了遍歷方式,使用者用起來簡單了。
2.可以進行多種遍歷方式的使用,方便了對集合的遍歷。
3.封裝性良好,只需要得到迭代器遍歷,而對於遍歷演算法則不用去關心,並且更好的封裝了內部的資訊細節。
迭代器模式的缺點:
1.對於比較簡單的遍歷,使用較為繁瑣。


迭代器的適用場景:

1.對於容器的自定義迭代。


=============================================================


最後為lpl的中國戰隊加油!在今年的S8世界總決賽中,希望他們能有個好成績!!
















相關文章