枚举器模式-Iterator Pattern -使用 foreach 语句、实现多个枚举器

一、两个概念

        1、聚集:所谓聚集就是一组数据集或者对象集,它可以通过循环来访问 。

        2、枚举器: 专门用来访问聚集的类,他包装了一定的方法,可以依次把聚集中的数据按照一定的顺序读出来。

        二、枚举器模式中出现的接口和类

        1、Aggregate 接口:抽象的聚集,通常只留有一个方法让子类去实现,这个方法的作用是获得一个枚举器对象,通常可以起名字为 GetIterator( )CreateIterator( ) 等等,或者干脆叫做 Iterator( ) 也行。在 C# 中,这个方法的名字叫做 GetEnumerator( ) ,这个我们到后面再讲。当然,在获得枚举器的同时,也要把自己 this(一组数据集)当作参数传给枚举器,想想也是,如果没有数据集,枚举器去枚举什么呢?

        2、ConcreteAggregate 类:具体的聚集,它的实例保存了一组数据集,同时它实现了 Aggregate 接口中唯一的那个方法,通常情况下他也会扩展出一些其他方法便于访问聚集中的数据,常见的有:访问某个位置数据的方法,可以叫做 GetElement(int index) 或者 GetItem(int index) 等等;获得聚集大小的方法,可以起名字为 GetLength( ) 或者 GetSize( ) 等等,全看自己喜好。

        3、Iterator 接口:抽象的枚举器,通常情况下会有三个方法留给子类去实现,他们分别是:Next( ) ,用来把指针移动到聚集中的下一个数据;HasNext( ) ,用来判断是否还有下一个数据;CurrentItem( ),返回当前指针所指位置的数据。也可以把 Next( ) CurrentItem( )
组成一个方法,在移动指针的同时返回一个数据。也可以有其他的实现方式,或者简单,或者复杂,也是全看个人需求。

        4、ConcreteIterator 类:具体的枚举器,它实现了上述的三个方法,通过不同的实现方式,我们可以获得不同的枚举方式,如顺序枚举、倒序枚举等等。当然,这个类的构造方法中会接受一个具体聚集参数,想想也是,如果没有这个数据集,他去枚举什么呢?这个参数就是他要去枚举的对象。

        5、被聚集的类,这个可以是任何类,它的许多个对象被存到聚集对象中才能形成一个真正的聚集,在我的例子中用的类叫 Book 类,它的四个实例即四本书形成一个聚集。下面看具体的代码吧。

        三、常规枚举器模式的代码实现

        这里用到“常规”这个词是指,这里的代码可以当作一个模版来用,不管你用的是 C# 还是 Java 或者是 Delphi ,均可以按照这个模版来实现枚举器模式。当然在 C# 和 Java 中,因为它们本身就支持枚举器模式,实现起来更方便一些,C#  的实现方法会在后面给出。

        我把客户端代码和模式类代码分别放在两个文件中。

        下面是模式类代码 Iterator.cs

using System; 
 
namespace Iterator 

    
/**//// <summary> 
    
/// 一个普通的书籍类,它的许多实例可以形成一个聚集 
    
/// </summary> 

    public class Book 
    

        
string name; 
         
        
public Book(string name) 
        

            
this.name=name; 
        }
 
 
        
public string GetName() 
        

            
return name; 
        }
 
    }
 
 
 
    
/**//// <summary> 
    
/// 抽象的聚集接口 
    
/// </summary> 

    public interface IAggregate 
    

        IIterator GetIterator(); 
    }
 
 
 
    
/**//// <summary> 
    
/// 书架,它是一个具体的聚集类,在这里是书的聚集 
    
/// 所有聚集的共同点是,它会创建一个枚举器 
    
/// 同时把自己当作参数传给枚举器,好让这个枚举器可以枚举自己 
    
/// </summary> 

    public class BookShelf:IAggregate 
    

        
private Book[] books; 
         
        
public BookShelf() 
        

            books
=new Book[4]; 
            books[
0]=new Book("Around the World in 80 Days"); 
            books[
1]=new Book("Bible"); 
            books[
2]=new Book("Cinderella"); 
            books[
3]=new Book("Dady-long-legs"); 
        }
 
 
        
public Book GetElement(int index) 
        

            
return books[index]; 
        }
 
 
        
public int GetLength() 
        

            
return books.Length ; 
        }
 
 
        
public IIterator GetIterator() 
        

            
//  把自己  一个书架实例  传到一个具体的枚举器中,好让枚举器工作 
            return new BookShelfIterator(this); 
        }
 
    }
 
 
 
    
/**//// <summary> 
    
/// 枚举器接口,抽象的,由它去枚举聚集 
    
/// </summary> 

    public interface IIterator 
    

        
bool HasNext(); 
        Object CurrentItem(); 
        
void Next(); 
    }
 
 
 
    
/**//// <summary> 
    
/// 具体的枚举器,在这里是一个书架 
    
/// 所有枚举器的特点是,他会在构造方法中得到一个具体的聚集实例,并用一定的方法去枚举他 
    
/// </summary> 

    public class BookShelfIterator:IIterator 
    

        
private BookShelf bookShelf; 
        
private int index; 
        
private int size; 
 
        
public BookShelfIterator(BookShelf bookShelf) 
        

            
//获得一个具体聚集,去枚举他 
            this.bookShelf=bookShelf; 
            index
=0
            size
=bookShelf.GetLength(); 
        }
 
 
        
public bool HasNext() 
        

            
if(index<size)        return true
            
else return false
        }
 
 
        
public Object CurrentItem() 
        

            
return bookShelf.GetElement(index); 
        }
 
 
        
public void Next() 
        

            
if(index<size) index++
        }
 
    }
 
}
 

     下面是客户端代码:Client.cs
using System; 
 
 
namespace Iterator 

    
class MainClass 
    

        [STAThread] 
        
static void Main(string[] args) 
        

            IIterator iterator; 
            IAggregate agg
=new BookShelf();//创建一个书架,书架上已经存了四本书 
             
            iterator
=agg.GetIterator();//创建一个可以枚举这个书架的枚举器 
            while(iterator.HasNext()) 
            

                Book book
=(Book)iterator.CurrentItem(); 
                Console.WriteLine(book.GetName()); 
                iterator.Next(); 
            }
 
            Console.Read(); 
        }
 
    }
 
}
 
 

 四、在 C#中枚举器模式的实现——使用 foreach 语句

        在 C# 中,因为 Aggregate 接口和 Iterator 接口,已经存在了,我们直接去实现他就可以了。 C# 中的Aggregate 接口叫做 IEnumerable,翻译过来是可以被枚举的,什么可以被枚举?当然就是聚集了。Iterator 接口叫做 IEnumerator ,是不是换汤不换药?如果上面的代码您已经看懂了,下面的代码应该也难不住你,我就不多说了,有注释。

        我把客户端代码和模式类代码分别放在两个文件中。

 

        下面是模式类代码 Iterator.cs


using System; 
using System.Collections ; 
 
namespace Iterator 

    
public class Book 
    

        
string name; 
         
        
public Book(string name) 
        

            
this.name=name; 
        }
 
 
        
public string Name 
        

            
get 
            

                
return name; 
            }
 
        }
 
    }
 
 
    
public class BookShelf:IEnumerable 
    

        
private Book[] books; 
         
        
public BookShelf() 
        

            books
=new Book[4]; 
            books[
0]=new Book("Around the World in 80 Days"); 
            books[
1]=new Book("Bible"); 
            books[
2]=new Book("Cinderella"); 
            books[
3]=new Book("Dady-long-legs"); 
        }
 
 
        
public Book GetElement(int index) 
        

            
return books[index]; 
        }
 
 
        
public int Length 
        

            
get 
            

                
return books.Length ; 
            }
 
        }
 
     
        
//实现 IEnumerable 接口的方法,得到一个枚举器,并把自己作为参数传给枚举器 
        public IEnumerator GetEnumerator() 
        

            Console.WriteLine(
"得到枚举器!"); 
            
return new BookShelfIterator(this);; 
        }
 
 
    }
 
     
 
    
public class BookShelfIterator:IEnumerator 
    

        
private BookShelf bookShelf; 
        
private int index; 
 
        
//得到一个聚集对象,可以去枚举他 
        public BookShelfIterator(BookShelf bookShelf) 
        

            
this.bookShelf=bookShelf; 
            index
=-1
        }
 
     
        
//实现 IEnumerator 的方法,将指针移动到下一个 
        public bool MoveNext() 
        

            
if(index<bookShelf.Length -1)  
            

                Console.Write(
"MoveNext->"); 
                index
++
                
return true
            }
 
            
else return false
        }
 
     
        
//实现 IEnumerator 的方法,将指针重置到起始位置 
        public void Reset() 
        

            index
=-1
            Console.WriteLine(
"Reset!"); 
        }
 
     
        
//实现 IEnumerator 的属性,返回当前指针所指的数据 
        public object Current 
        

            
get 
            

                Console.Write(
"GetCurrent->"); 
                
return bookShelf.GetElement(index); 
            }
 
        }
 
    }
 
}
 

 下面是客户端代码:Client.cs      
using System; 
 
namespace Iterator 

    
class MainClass 
    

        [STAThread] 
        
static void Main(string[] args) 
        

            BookShelf agg
=new BookShelf();//创建一个书架,书架上已经存了四本书 
            foreach(Book book in agg)  Console.WriteLine(book.Name);     
            Console.Read(); 
        }
 
    }
 
}
 

关于这两段代码,用分步运行就可以搞清楚 foreach 是怎么运作的了。但我还是要解释一下。

        1、首先 in 后面的变量一定得是个聚集,即必须返回一个 IEnumerable 类型的对象。在这里我们直接给它了,就是 agg 。但当你想实现多种枚举方式的时候,就必须知道这一点。所以再重复一遍,in 后面的变量必须是一个 IEnumerable 类型的对象。

        2、当循环开始启动时, 首先运行的是 in 后面那个聚集对象的 GetEnumerator( ) 方法,它返回一个枚举器,并把聚集自身当作参数传给枚举器。这个枚举器到底返回给谁了?我不知道,但是有一点我很清楚,这个方法 return 的是哪个枚举器的实例, foreach 就会用哪个枚举器的方式去枚举数据。当你想实现多种枚举方式的时候,你必须知道这一点。这里我们只用到了一个枚举器,后面我们会举一个两个枚举器的例子。

        3、当确定使用哪个枚举器以后, foreach  接着会调用这个枚举器的 MoveNext( ) 方法,什么都没干先移动一下?很奇怪吧?就是这样!所以注意 index 要从 -1 开始。

        4、每 MoveNext( )  下,接着就调用  Current 属性,返回当前指针指向的数据。

        5、当 MoveNext( ) 返回 false 时,一个  foreach  过程就结束了。

运行效果如下图:

        五、一个聚集实现多个枚举器——使用 foreach 语句


下面是模式类代码 Iterator.cs
using System; 
using System.Collections ; 
 
namespace Iterator 

    
/**//// <summary> 
    
///  
    
/// </summary> 

    public class Book 
    

        
string name; 
         
        
public Book(string name) 
        

            
this.name=name; 
        }
 
 
        
public string Name 
        

            
get 
            

                
return name; 
            }
 
        }
 
    }
 
 
 
    
/**//// <summary> 
    
///  
    
/// </summary> 

    public class BookShelf:IEnumerable 
    

        
private Book[] books; 
        
private IEnumerator iterator; 
         
        
public BookShelf() 
        

            books
=new Book[4]; 
            books[
0]=new Book("Around the World in 80 Days"); 
            books[
1]=new Book("Bible"); 
            books[
2]=new Book("Cinderella"); 
            books[
3]=new Book("Dady-long-legs"); 
 
            iterator
=new DefaulIterator(this); 
        }
 
 
        
public Book GetElement(int index) 
        

            
return books[index]; 
        }
 
 
        
public int Length 
        

            
get 
            

                
return books.Length ; 
            }
 
        }
 
     
        
public IEnumerator GetEnumerator() 
        

            Console.WriteLine(
"得到枚举器!"); 
            
return iterator; 
        }
 
         
        
public IEnumerable GetOrderBooks() 
        

            iterator
=new DefaulIterator(this); 
            
return  this
        }
 
 
 
        
public IEnumerable GetReverseBooks() 
        

            iterator
=new OtherIterator(this); 
            
return  this
        }
 
    }
 
     
 
    
/**//// <summary> 
    
/// 
    
/// </summary> 

    public class DefaulIterator:IEnumerator 
    

        
private BookShelf bookShelf; 
        
private int index; 
 
        
public DefaulIterator(BookShelf bookShelf) 
        

            
//获得一个具体聚集,去枚举他 
            this.bookShelf=bookShelf; 
            index
=-1
        }
 
     
        
public bool MoveNext() 
        

            
if(index<bookShelf.Length -1)  
            

                Console.Write(
"MoveNext->"); 
                index
++
                
return true
            }
 
            
else return false
        }
 
     
        
public void Reset() 
        

            index
=-1
            Console.WriteLine(
"Reset!"); 
        }
 
     
        
public object Current 
        

            
get 
            

                Console.Write(
"GetCurrent->"); 
                
return bookShelf.GetElement(index); 
            }
 
        }
 
    }
 
 
 
 
    
/**//// <summary> 
    
/// 
    
/// </summary> 

    public class OtherIterator:IEnumerator 
    

        
private BookShelf bookShelf; 
        
private int index; 
 
        
public OtherIterator(BookShelf bookShelf) 
        

            
//获得一个具体聚集,去枚举他 
            this.bookShelf=bookShelf; 
            index
=4
        }
 
     
        
public bool MoveNext() 
        

            
if(index>0)  
            

                Console.Write(
"MoveNext->"); 
                index
--
                
return true
            }
 
            
else return false
        }
 
     
        
public void Reset() 
        

            index
=4
            Console.WriteLine(
"Reset!"); 
        }
 
     
        
public object Current 
        

            
get 
            

                Console.Write(
"GetCurrent->"); 
                
return bookShelf.GetElement(index); 
            }
 
        }
 
    }
 
 
 
}
 

下面是客户端代码:Client.cs    
using System; 
 
namespace Iterator 

    
class MainClass 
    

        [STAThread] 
        
static void Main(string[] args) 
        

 
            BookShelf agg
=new BookShelf();//创建一个书架,书架上已经存了四本书 
 
            
foreach(Book book in agg.GetOrderBooks())  Console.WriteLine(book.Name); 
            
foreach(Book book in agg.GetReverseBooks())  Console.WriteLine(book.Name); 
 
            Console.Read(); 
        }
 
    }
 
}
 

运行效果如下图:

posted @ 2007-12-26 12:44  啸翱姜糊  阅读(188)  评论(0编辑  收藏  举报