天天看點

Java設計模式之疊代器模式群組合模式

疊代器模式

疊代器模式定義為,提供一種方法順序通路聚合對象中的各個元素,又不暴露其内部的表示方法。

疊代器模式允許通路聚合中的各個元素,為客戶提供了統一的方法去通路各個集合,屏蔽了具體集合的類型,無論是List,Map,Set,散清單,數組等集合,在用戶端表現的都是一種方法來擷取該集合中的元素。

通常疊代器将周遊聚合的工作封裝進一個對象中,在我們使用疊代器的時候,我們依賴聚合提供周遊,通常聚合都會傳回一個疊代器。這樣就可以讓集合隻專注于元素的操作,而将對于元素遊走的周遊工作放在疊代器上執行,這樣就可以簡化聚合的接口和實作。如果你有一個統一的方法來通路聚合中的每一個對象,則就可以利用多态的代碼和這些聚合搭配。

疊代器類圖如下:

Aggregate:集合接口,提供了一個方法來給用戶端來傳回一個對于聚合元素通路周遊的疊代器。

ConcreteAggregate:具體聚合持有了一個對象的集合,每一個具體聚合都要負責執行個體化與之對應的具體疊代器,此疊代器能夠周遊對象集合。

Iterator:這是所有疊代器都要實作的接口,一般可以直接實作Java系統自帶的Iterator。

ConcreteIterator:對于特定聚合對象進行周遊的算法。它主要負責周遊對象,以及判斷對象。

注:在常用的各種集合對象中,list,Set均可以直接調用它們的方法List.iterator();和Set.iterator();

一般對于如果是數組類型的,則就需要專門為數組做一個疊代器來轉換它的周遊方式

對于Map集合的,由于Map集合是鍵值對的,是以要想取得它的值,

Map.values.iterator();//首先傳回值的對象所有集合,然後再生成疊代器

一般疊代器是向前移動的,但是也可以實作向後移動,有一個ListIterator,這個可以實作向後移動元素的通路。疊代器周遊的結果并不是表示元素的大小次序的。在利用疊代器中,當一個方法的參數是一個疊代器的時候,其實就是使用了多态,我們此時針對接口程式設計而不是具體類程式設計,進而可以在不同的集合中周遊。

當然如果不想建立疊代器,可以直接利用foreach

代碼示例:

有三個聚合類,一個用ArrayList存儲對象,一個用數組存儲對象,一個利用HashMap。由于三個集合通路周遊集合中的元素不同,但是為了給用戶端提供一個統一的通路方法,此時就可以利用疊代器模式,為每一個集合建立一個對象的疊代器,再在聚合類中執行個體化該疊代器傳回給用戶端,這樣用戶端就隻管周遊,而不用關心具體的集合類型了。

集合接口:存放元素的集合,并且為用戶端傳回一個集合的疊代器

package com.whut.iterator;

import java.util.Iterator;

public interface Menu {

public Iterator createIterator();

}

利用數組存儲對象的具體集合

publicclass DinerMenu implements Menu{

privatestaticfinalint MAX_ITEMS=6;

privateint numberOfItems=0;

private MenuItem[] menuItems;

public DinerMenu()

{

menuItems=new MenuItem[MAX_ITEMS];

addItem("Dinner Vegetarian","Bacon",true,2.99);

addItem("Dinner BLT ","Bacon BLT",false,2.99);

addItem("Dinner hotdog","A hot dog",false,3.48);

publicvoid addItem(String name,String description,boolean vegetarian,double price)

MenuItem item=new MenuItem(name,description,vegetarian,price);

if(numberOfItems<MAX_ITEMS)

menuItems[numberOfItems]=item;

numberOfItems++;

else

System.out.println("Sorry ,menu is full");

public Iterator createIterator()

return new DinerMenuIterator(menuItems);

利用ArrayList存儲對象的具體集合

import java.util.ArrayList;

publicclass PancakeHouseMenu implements Menu{

private ArrayList menuItems;

public PancakeHouseMenu()

menuItems=new ArrayList();

addItem("K&B panckage breakfast","pancakes with scramed eggs and toast",true,2.99);

addItem("Regular panckage breakfast","pancakes with fried eggs ",false,2.99);

addItem("Blueberry breakfast","pancakes made with fresh blueberry ",true,3.48);

addItem("Waffles","waffles, with your choice",true,3.59);

menuItems.add(item);

return menuItems.iterator();

利用HashMap存儲對象的具體集合

import java.util.HashMap;

publicclass CoffeeMenu implements Menu{

private HashMap menuItems=new HashMap(); 

public CoffeeMenu()

addItem("Coffee Burger" ,"veggie burger on",true,3.99);

addItem("Coffee Soup","A cup of the soup",false,3.69);

addItem("Coffee Burrito","A large burrito",true,4.29);

menuItems.put(item.getName(),item);

@Override

public Iterator createIterator() {

// TODO Auto-generated method stub

//直接傳回一個疊代器

return menuItems.values().iterator();

由于為了統一數組和ArrayList和HashMap的周遊方法,需要為數組建立一個疊代器

publicclass DinerMenuIterator implements Iterator {

private MenuItem[] items;

privateint position=0;//存放目前周遊的坐标

public DinerMenuIterator(MenuItem[] items)

this.items=items;

public boolean hasNext() {

if(position>=items.length || items[position]==null)

return false;

return true;

public Object next() {

MenuItem menuItem=items[position];

position=position+1;

return menuItem;

public void remove() {

if(position<=0)

throw new IllegalStateException("You can't remove an item at least");

if(items[position]!=null)

for(int i=position-1;i<items.length-1;i++)

items[i]=items[i+1];

items[items.length-1]=null;

提供一個來測試

public class Waitress {

private Menu diner;

private Menu house;

private Menu cafe;

public Waitress(Menu diner,Menu house,Menu cafe)

this.diner=diner;

this.house=house;

this.cafe=cafe;

publicvoid printMenu()

Iterator houseIterator=house.createIterator();

Iterator dinerIterator=diner.createIterator();

Iterator cafeIterator=cafe.createIterator();

System.out.println("-------houseMenu--------");

printMenuItem(houseIterator);

System.out.println();

System.out.println("-------dinnerMenu--------");

printMenuItem(dinerIterator);

System.out.println("-------coffeeMenu--------");

printMenuItem(cafeIterator);

private void printMenuItem(Iterator iterator)

while(iterator.hasNext())

MenuItem menuItem=(MenuItem)iterator.next();

System.out.print(menuItem.getName()+"_||_"+menuItem.getPrice()

+"_||_"+menuItem.getDescription());

設計原則:一個類應該隻有一個引起變化的原因。

組合模式

組合模式定義為,允許你将對象組合成樹形結構來表現“整體/部分”層次結構。組合能讓客戶以一緻的方式處理個别對象以及組合對象。

組合模式,能夠讓我們用樹形方式建立對象的結構,樹裡面包含了組合以及個别對象。我們可以把相同的操作應用到組合對象和個别對象中。

在這種模式中,組合對象是可以包含個别對象的,而個别對象就是樹形結構中的葉子節點。

一般利用組合模式,組合對象和個别對象均要實作同樣的接口。組合模式應用場景主要是在當有多個對象的時候,他們彼此之間有“整體/部分”的關系,并且想要給客戶一種一緻的方法來對待這些對象的時候,就需要這種模式。組合模式能夠使的客戶不再擔心面對的是組合對象或者個别對象,他們隻需要對整個結構調用一個方法就可以執行所需要的周遊操作了。

代碼執行個體:

組合對象和個别對象均要實作相同接口

package com.whut.composite;

//組合需要和葉子節點一樣實作相同的接口

publicclass Flock implements Quackable {

private ArrayList quackers=new ArrayList();

publicvoid add(Quackable quacker)

quackers.add(quacker);

//通過實作相同的接口,就能保證每次循環周遊完所有的單個對象和對象集合

publicvoid quack() {

Iterator iterator=quackers.iterator();

Quackable quacker=(Quackable) iterator.next();

quacker.quack();//注意這裡

小技巧:

在我們設計類的時候,如果有些方法隻是針對某一些子類型使用,而有一些針對其它子類型使用,為了防止各個子類非法去實作不屬于自己的方法,可以在抽象類中的方法中直接throw new UnsupportedOperationException()。這樣子類如果不需要該方法,就直接繼承預設的。

本文轉自 zhao_xiao_long 51CTO部落格,原文連結:http://blog.51cto.com/computerdragon/1168807