迭代器模式和组合模式混用
迭代器模式和組合模式混用
前言
園子里說設計模式的文章算得上是海量了,所以本篇文章所用到的迭代器設計模式和組合模式不提供原理解析,有興趣的朋友可以到一些前輩的設計模式文章上學學,很多很有意思的。在Head First 設計模式這本書中,也有說迭代和組合模式混用的方法,但是使用的語言是JAVA,實現起來比起C#差異還是不少。本人在做幾個C#小項目的時候需要用到樹形結構,也看到了Head First 設計模式中混用迭代器和組合模式的例子,覺得如果能用C#實現,以后無疑會帶來很大的幫助。下面就記錄下實現過程,希望有不好的地方,各位前輩大力拍,晚生會努力改正,本文使用C#。
?
效果與目標
1.能自動遍歷樹形結構中的所有節點。
2.對樹中所有節點進行統一管理,統一到一個根節點上。
舉個例子:文件系統,有文件夾和文件這兩個類型,形成一個文件系統樹形結構,使用了本文章所說的混用模式以后,能輕松對每一個結點進行自動處理,最簡單的就是打印各自的名字和子文件系統或排序等。
?
實現過程
下面以文件系統為例,可以根據需要靈活改變,主要講得是思想而已。
?新建一個C#控制臺,隨便改個名字。
?搭建類和接口(實現組合模式)。
1.IFileSystemNode(文件系統接口):
interface IFileSystemNode{String Name { set; get; }String Path { set; get; }List<IFileSystemNode> Children { set; get; }IEnumerator getIterator();void ShowName();} View Code2.FolderNode(文件夾節點類):
class FolderNode : IFileSystemNode{public FolderNode(String name, String path){this.Name = name;this.Path = path;}private string _name;public string Name{get{return _name;}set{_name = value;}}private string _path;public string Path{get{return _path;}set{_path = value;}}private List<IFileSystemNode> _children = new List<IFileSystemNode>();public List<IFileSystemNode> Children{get{return _children;}set{_children = value;}}public void ShowName(){Console.WriteLine(Name);}public System.Collections.IEnumerator getIterator(){throw new NotImplementedException();}} View Code?3.FileNode(文件節點類):
class FileNode : IFileSystemNode{public FileNode(String name, String path){this.Name = name;this.Path = path;}private string _name;public string Name{get{return _name;}set{_name = value;}}private string _path;public string Path{get{return _path;}set{_path = value;}}public List<IFileSystemNode> Children{get{throw new NotImplementedException();}set{throw new NotImplementedException();}}public void ShowName(){Console.WriteLine(Name);}public System.Collections.IEnumerator getIterator(){throw new NotImplementedException();}} View Code注意:以上實現了組合模式,其中getIterator方法是還沒有代碼的,這個需要使用迭代器模式。
?編寫迭代器(實現迭代器模式)。
在FolderNode中有子節點,但是在FileNode中沒有子節點,但是因為使用了組合器模式,對于FolderNode和FileNode,都需要實現相同的契(IFileSystemNode)。所以在FolderNode中返回的迭代器是用來迭代子節點,而FileNode則不同,它根本沒有子節點,那么就使用一個叫做空迭代器來滿足契約。
? ? ? ? ?下面分別實現具體迭代器(繼承C#系統提供的IEnumerator接口)。
1.為FolderNode提供具體迭代器:FolderNodeIterator
class FolderNodeIterator : IEnumerator{private IEnumerable<IFileSystemNode> fileSystems { set; get; }public FolderNodeIterator(IEnumerable<IFileSystemNode> _fileSystems){this.fileSystems = _fileSystems;}private int currentIndex = -1;public object Current{get { return fileSystems.ElementAt(currentIndex); }}public bool MoveNext(){if (currentIndex < fileSystems.Count() - 1){currentIndex++;return true;}return false;}public void Reset(){currentIndex = -1;}} View Code新建完類以后,我們修改下FolderNode類中的getIterator方法,返回一個FolderNodeIterator實例,代碼如下:
public IEnumerator getIterator(){return new FolderNodeIterator(_children);}?2.為FileNode提供具體迭代器:EmptyIterator
class EmptyIterator : IEnumerator{public object Current{get { return null; }}public bool MoveNext(){return false;}public void Reset(){}} View Code新建完類以后,我們同樣修改下FileNode類中的getIterator方法,返回一個EmptyIterator實例,代碼如下:
public IEnumerator getIterator(){return new EmptyIterator();}
使用
?
好像差不多了,我們使用使用一下這個模型:
為了添加真實性,本演示映射了真實文件系統,請在Programe類上添加一個靜態方法:Convert
private static void Convert(FolderNode root, String directoryPath){foreach (var filesystempath in Directory.EnumerateFiles(directoryPath)){if (root.Children != null){root.Children.Add(new FileNode(Path.GetFileName(filesystempath), filesystempath));}}foreach (var filesystempath in Directory.EnumerateDirectories(directoryPath)){FolderNode newFolderNode = new FolderNode(Path.GetFileName(filesystempath), filesystempath);root.Children.Add(newFolderNode);Convert(newFolderNode, filesystempath);}} View Code然后我們在Main方法中就能先映射,再使用,來看一下Main方法,其中使用了迭代器模式去迭代各個子項:
static void Main(string[] args){FolderNode root = new FolderNode(@"酷狗音樂", @"C:\Users\Administrator\Desktop\\酷狗音樂");Convert(root, @"C:\Users\Administrator\Desktop\\酷狗音樂");IEnumerator Myiterator = root.getIterator();while (Myiterator.MoveNext()){IFileSystemNode ctextIterator = (IFileSystemNode)Myiterator.Current;ctextIterator.ShowName();}Console.ReadKey();}我映射了桌面上的一個文件,看看文件結構:
有一個hozin文件夾(里面有3首歌),一個L'theme文件夾(里面有一首歌),一個文件(08開頭的歌)。
好了,運行程序,看看結果:,好像有點問題,為什么只有一個層的呢?也就是說,為什么只迭代了root節點的一層子節點,子節點的子節點還沒有遍歷完,這是因為FolderNodeIterator的迭代只提供了一層迭代,而不會深層迭代。所以如果想要深層迭代,使用Head First設計模式中的思想就是:提供一個組合迭代器,用來包裝FolderNodeIterator,提供深層迭代功能。下面是我在C#中的實現代碼,添加這樣一個類:CompositeIterator
class CompositeIterator : IEnumerator{public CompositeIterator(IEnumerator ienumerator){temp.Push(ienumerator);root = ienumerator;}IEnumerator root;Stack<IEnumerator> temp = new Stack<IEnumerator>();private IFileSystemNode _current;public object Current{get { return _current; }}public bool MoveNext(){if (temp.Count <= 0){return false;}if (temp.Peek().MoveNext()){_current = temp.Peek().Current as IFileSystemNode;IEnumerator ienumerator = _current.getIterator();if (ienumerator.MoveNext()){ienumerator.Reset();temp.Push(ienumerator);}}else{temp.Pop();MoveNext();}if (temp.Count <= 0){return false;}else{return true;}}public void Reset(){temp.Clear();temp.Push(root);}} View Code然后,修改FolderNode類中的getIterator方法如下:
public System.Collections.IEnumerator getIterator(){return new CompositeIterator(new FolderNodeIterator(this._children));}包裝完以后,再次運行:。OK大功告成
?
總結
為了適應真實項目,可以改的點有很多:
1.這里只有FolderNode和FileNode,在實際項目中可能不止,可以添加,只要繼承同一個接口(這里是IFileSystemNode),那么就能像皇帝發號命令一樣命令所有子子孫孫做事情了(在root節點上調用IFileSystemNode上聲明有的方法)。
2.添加契約方法,例如像要對每一個節點進行排序Sort,直接添加一個方法,然后子孫各自實現方法,最后調用root節點的Sort。
3.這里的遍歷使用前序遍歷,遍歷樹的所有節點,但是也可以使用您喜歡的方式,只要修改組合迭代器。
?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?源碼下載
轉載于:https://www.cnblogs.com/Jarvin/p/3735460.html
總結
以上是生活随笔為你收集整理的迭代器模式和组合模式混用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 实例介绍Cocos2d-x开关菜单
- 下一篇: Fatal error: cannot