您的位置:首页 > 其它

HeadFirst 设计模 4000 式 9迭代器与组合模式(餐厅合并)

2015-08-17 13:55 447 查看
迭代器模式

提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。

迭代器模式让我们能够游走于聚合内的每个元素,而又不暴露其内部的表示。把游走的任务放在迭代器上,而不是聚合上。这样简化了聚合的接口和实现,也让责任各得其所。

集合collection/聚合aggregate:指一群对象,其存储方法可以是各式各样的数据结构,例如:列表、数组、散列表,无论用什么方式存储,一律可以视为是集合/聚合。



实例:

public class MenuItem{
String name;
String description;
boolean vegetarian;
double price;

public MenuItem(String name,String description,boolean vegetarian,double price){
this.name=name;
this.description=description;
this.vegetarian=vegetarian;
this.price=price;
}
public String getName(){ return name;}
public String getDescription(){ return description;}
public double getprice(){ return price;}
public boolean isVegetarian(){ return vegetarian;}
}

public interface Iterator{
boolean hasNext(); //返回一个布尔值,判断是否还有更多的元素
Object next(); //返回下一个元素
}

//实现迭代器接口 DinerMenu
public class DinerMenuIterator implements Iterator{
MenuItem[] items;
int position = 0; //position记录当前数组遍历的位置

public DinerMenuIterator(MenuItem[] items){ //构造器需要被传入一个菜单项的数组当作参数
this.items=items;
}

public Object next(){ //返回数组内的下一项,并递增其位置
MenuItem menuItem= items[position];
position=position+1;
return menuItem;
}

public boolean hasNext(){
/*检查是否已经取得数组内所有的元素,如果还有元素待遍历则返回true;
由于使用的是固定长度的数组,所以不但要检查是否超出了数组长度,也必须检查是否下一项是null,如果是null,就没有其他项了
*/
if(position>=items.length||items[position]==null){
return false;
}else{
return true;
}
}
}

//实现迭代器接口 PancakeHouseMenu
public class PancakeHouseMenuIterator implements Iterator{
ArrayList items;
int position = 0; //position记录当前数组遍历的位置

public PancakeHouseMenuIterator(ArrayList items){ //构造器需要被传入一个菜单项的数组当作参数
this.items=items;
}

public Object next(){ //返回数组内的下一项,并递增其位置
MenuItem menuItem= items.get(position);
position=position+1;
return menuItem;
}

public boolean hasNext(){
if(position>=items.size()||items.get(position)==null){
return false;
}else{
return true;
}
}
}

public class DinerMenu{
static final int MAX_ITEMS=6;
int numberOfItems=0;
MenuItem[] menuItems;

public DinerMenu(){
menuItems=new MenuItem[MAX_ITEMS];

addItem("Vegetarian BLT","1111111111111",true,2.99);
addItem("BLT","222222222222",false,2.99);
addItem("Soup of the day","2222222222222",false,3.29);
addItem("Hotdog","33333333333333",false,3.05);
//继续加入其他项
}

public void addItem(String name,String description,boolean vegetarian,double price){
MenuItem menuItem= new MenuItem(name,description,vegetarian,price);
if(numberOfItems>=MAX_ITEMS){
System.err.println("Sorry,menu is full! Can't add item to menu");
}else{
menuItems[numberOfItems]=menuItem;
numberOfItems=numberOfItems+1;
}
}

//返回迭代器接口。客户不需要知道餐厅菜单是如何维护菜单项的,也不需要知道迭代器是如何实现的,客户只需要直接使用这个迭代器遍历菜单项即可。
public Iteraor createIterator(){
return new DinerMenuIterator(menuItems);
}
//菜单的其他方法。。。。
}

public class PancakeHouseMenu{
ArrayList menuItems;

public PancakeHouseMenu(){
menuItems=new ArrayList();
addItem("K&B's Pancake Breakfast","1111111111111",true,2.99);
addItem("Regular Pancake Breakfast","222222222222",false,2.99);
addItem("Blueberry Pancakes","2222222222222",true,3.29);
addItem("Waffles","33333333333333",true,3.05);
}

public void addItem(String name,String description,boolean vegetarian,double price){
MenuItem menuItem= new MenuItem(name,description,vegetarian,price);
menuItems.add(menuItem);
}

public Iteraor createIterator(){
return new PancakeHouseMenuIterator(menuItems);
}
//其他方法
}

public class Waitress{
PancakeHouseMenu pancakeHouseMenu;
DinerMenu dinerMenu;
//在构造器中,女招待照顾两个菜单
public Waitress(PancakeHouseMenu pancakeHouseMenu,DinerMenu dinerMenu){
this.pancakeHouseMenu=pancakeHouseMenu;
this.dinerMenu=dinerMenu;
}
public void printMenu(){
Iterator pancakeIterator=pancakeHouseMenu.createIterator();
Iterator dinerIterator=dinerMenu.createIterator();
System.out.println("Menu\n-------------\nBREAKFAST");
printMenu(pancakeIterator);
System.out.println("\nLUNCH");
printMenu(dinerIterator);
}
private void printMenu(Iterator iterator){ //重载printMenu方法,使用迭代器遍历菜单项并打印
while(iterator.hasNext()){
MenuItem menuItem=(MenuItem)iterator.next();
System.out.print(menuItem.getName()+",");
System.out.print(menuItem.getPrice()+"--");
System.out.println(menuItem.getDescription());
}
}
//其他方法
}

public class MenuTestDriver{
public static void main(String args[]){
PancakeHouseMenu pancakeHouseMenu=new PancakeHouseMenu();
DinerMenu dinerMenu= new DinerMenu();
Waitress waitress=new Waitress(pancakeHouseMenu,dinerMenu);
waitress.printMenu();
}
}类图



进一步改进:为两份菜单设立共同的接口。



设计原则

一个类应该只有一个引起变化的原因。

类的每个责任都有改变的潜在区域。超过一个责任则意味着多个改变的区域。该原则说明了应该尽量让每个类保持单一责任。

组合模式

允许将对象组合成树形结构来表现“整体/部分”层次结构。组合能够让客户以抑制的方式处理个别对象以及对象组合。

组合模式让我们 能用树形方式创建对象的结构,树里面包含了组合以及个别的对象。使用组合结构,我们能把相同的操作应用在组合和个别对象上。即:在大多数情况下,我们可以忽略对象组合和个别对象的差别。



区别各类模式:

策略模式:封装可互换的行为,并使用委托决定使用哪一个。

适配器模式:改变一个或多个类的接口。

迭代器模式:提供一个方式来遍历集合,而无需暴露集合的实现。

外观模式:简化一群类的接口。

组合模式:客户可以将对象的集合以及个别的对象一视同仁。

观察者模式:当某个状态改变是,允许一群对象能被通知到。

要点:

(1)迭代器允许访问聚合的元素,而不需暴露他的内部结构。

(2)迭代器将遍历聚合的工作封装进一个对象中。

(3)当使用迭代器的时候,我们依赖聚合提供遍历。

(4)迭代器提供一个通用的接口,让我们遍历聚合的项,当我们编码使用聚合的项时,就可以使用多态机制。

(5)我们应该努力让一个类只分配一个责任。

(6)组合模式提供一个结构,可同时包容个别对象和组合对象。

(7)组合模式允许客户对个别对象和组合对象一视同仁。

(8)组合结构内的任意对象称为组件,组件可以是组合,也可以是叶节点。

(9)在实现组合模式时,有许多设计上的折中。要根据需要平衡透明性和安全性。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: