C#設(shè)計(jì)模式實(shí)現(xiàn)之迭代器模式
前言:
迭代器模式平時(shí)用的不多,因?yàn)椴还蹸#還是Java都已經(jīng)幫我封裝了,但是你是否知道平時(shí)經(jīng)常在用的東西本質(zhì)是怎么回事呢。
看完迭代器模式你就知道C# foreach循環(huán)是怎么實(shí)現(xiàn)的了,我的另一篇C# Foreach循環(huán)本質(zhì)與枚舉器就講解了foreach的本質(zhì),其中用到的就是迭代器模式。
按照慣例,例子走起。(寫了幾個(gè)小時(shí)瀏覽器崩潰,我看見在自動(dòng)保存啊,結(jié)果沒內(nèi)容,再擼一遍精簡(jiǎn)點(diǎn)的吧)
一、餐館合并菜單
現(xiàn)在有兩個(gè)餐館和并,其中一個(gè)餐館做早餐,一個(gè)做晚餐。他們都有自己管理菜單的方式,現(xiàn)在兩個(gè)餐館合并需要對(duì)菜單進(jìn)行統(tǒng)一管理,先讓我來看看他們?cè)瓉淼臉幼印?br />
兩個(gè)菜單的菜單項(xiàng)都是一樣的
public class MenuItme { //名字 public string Name { get; set; } //描述 public string Description { get; set; } //是否素菜 public bool Vegetarian { get; set; } //價(jià)格 public double Price { get; set; } public MenuItme(string name, string description, bool vegetarian, double price) { Name = name; Description=description; Vegetarian = vegetarian; Price = price; } }
早餐菜單,使用List管理,不限制長(zhǎng)度
public class BreakFastMenu { private List<MenuItme> menuItmes; public BreakFastMenu() { menuItmes = new List<MenuItme>(); AddItem("梅菜扣肉餅", "好吃", false, 7); //菜單項(xiàng)... } public void AddItem(string name, string description, bool vegetarian, double price) { MenuItme menuItme = new MenuItme(name, description, vegetarian, price); menuItmes.Add(menuItme); } public List<MenuItme> GetMenuItmes() { return menuItmes; } }
晚餐菜單,使用數(shù)組管理,限制長(zhǎng)度為6
public class DinerMenu { static readonly int Max_Items = 6; private int numberOfImtes = 0; private MenuItme[] menuItmes; public DinerMenu() { menuItmes = new MenuItme[Max_Items]; AddItem("爆炒癩蛤蟆", "講究火候", false, 42); //菜單項(xiàng)... } public void AddItem(string name, string description, bool vegetarian, double price) { MenuItme menuItme = new MenuItme(name, description, vegetarian, price); if (numberOfImtes >= Max_Items) { Console.WriteLine("菜單已滿"); } else { menuItmes[numberOfImtes] = menuItme; numberOfImtes++; } } public MenuItme[] GetMenuItmes() { return menuItmes; } }
當(dāng)兩個(gè)餐館合并后需要打印早餐和晚餐菜單給顧客用。
BreakFastMenu breakFastMenu = new BreakFastMenu(); List<MenuItme> breakFastMenus = breakFastMenu.GetMenuItmes(); DinerMenu dinerMenu = new DinerMenu(); MenuItme[] dinerMenus = dinerMenu.GetMenuItmes(); //打印早餐 for (int i = 0; i < breakFastMenus.Count; i++) { Console.WriteLine(breakFastMenus[i].Name); } //打印晚餐 for (int i = 0; i < dinerMenus.Length; i++) { Console.WriteLine(dinerMenus[i].Name); }
按照這種做法我們總是需要處理兩個(gè)菜單,如果要打印素食,那么也需要循環(huán)遍歷兩個(gè)菜單。
假如加入第三家餐廳合并,我們就需要循環(huán)處理三次,顯然這種方式會(huì)讓我們系統(tǒng)難以維護(hù)。
接下來看我們?nèi)绾芜M(jìn)行改進(jìn)
二、改進(jìn)菜單實(shí)現(xiàn)
計(jì)模式就是要封裝變化的部分,很明顯,這里變化是:不同的集合類所造成的遍歷,我們?nèi)绾畏庋b遍歷集合
不管早餐還是晚餐我們都要用到中括號(hào)[ ] 來取菜單項(xiàng),集合長(zhǎng)度來限制長(zhǎng)度。
現(xiàn)在我們要?jiǎng)?chuàng)建一個(gè)對(duì)象,將他稱為迭代器(Iterator),利用它來封裝“遍歷集合內(nèi)的每個(gè)對(duì)象的過程”。
對(duì)于List
Iterator iterator = breakFastMenu.CreateIterator(); while (iterator.HasNext) { MenuItme menuItme = iterator.Next(); }
對(duì)于數(shù)組
Iterator iterator = dinerFastMenu.CreateIterator(); while (iterator.HasNext) { MenuItme menuItme = iterator.Next(); }
現(xiàn)在兩個(gè)集合的遍歷都統(tǒng)一了,而這種方式正是迭代器模式。關(guān)于迭代器我們需要知道的第一件事情,就是它依賴于一個(gè)迭代器接口。
這個(gè)接口可能有HasNext()方法高數(shù)我們是否在這個(gè)集合中還有更多的元素。
Next()方法返回這個(gè)集合中的下一個(gè)對(duì)象。一旦我們有了這個(gè)接口,就可以為各種對(duì)象集合實(shí)現(xiàn)迭代器。
現(xiàn)在我們對(duì)晚餐菜單進(jìn)行改造,首先我們需要定義一個(gè)迭代器接口
public interface Iterator { bool HasNext(); Object Next(); }
加入一個(gè)晚餐菜單迭代器
public class DinerMenuIterator : Iterator { MenuItme[] menuItmes; int position = 0; public DinerMenuIterator(MenuItme[] menuItmes) { this.menuItmes = menuItmes; } public bool HasNext() { //由于數(shù)組是固定長(zhǎng)度,不僅要檢查數(shù)組,還要檢查指定位置是否為空,如果為空后面就沒有菜單項(xiàng)了 if (position >= menuItmes.Length || menuItmes[position] == null) return false; else return true; } public object Next() { MenuItme menuItme = menuItmes[position]; position++; return menuItme; } }
用迭代器改寫晚餐菜單
public class DinerMenu { static readonly int Max_Items = 6; private int numberOfImtes = 0; private MenuItme[] menuItmes; public DinerMenu() { menuItmes = new MenuItme[Max_Items]; AddItem("爆炒癩蛤蟆", "講究火候", false, 42); //菜單項(xiàng)... } public void AddItem(string name, string description, bool vegetarian, double price) { MenuItme menuItme = new MenuItme(name, description, vegetarian, price); if (numberOfImtes >= Max_Items) { Console.WriteLine("菜單已滿"); } else { menuItmes[numberOfImtes] = menuItme; numberOfImtes++; } } public Iterator CreateIterator() { return new DinerMenuIterator(menuItmes); } //public MenuItme[] GetMenuItmes() //{ // return menuItmes; //} }
同理我們?yōu)樵绮图尤氲?br />
public class BreakFastIterator: Iterator { List<MenuItme> menuItmes; int position = 0; public BreakFastIterator(List<MenuItme> menuItmes) { this.menuItmes = menuItmes; } public bool HasNext() { if (position >= menuItmes.Count) return false; else return true; } public object Next() { MenuItme menuItme = menuItmes[position]; position++; return menuItme; } }
用迭代器改寫早餐菜單
public class BreakFastMenu { private List<MenuItme> menuItmes; public BreakFastMenu() { menuItmes = new List<MenuItme>(); AddItem("梅菜扣肉餅", "好吃", false, 7); //菜單項(xiàng)... } public void AddItem(string name, string description, bool vegetarian, double price) { MenuItme menuItme = new MenuItme(name, description, vegetarian, price); menuItmes.Add(menuItme); } public Iterator CreateIterator() { return new BreakFastIterator(menuItmes); } //public List<MenuItme> GetMenuItmes() //{ // return menuItmes; //} }
好了,讓我們?cè)囈辉嚨鞴ぷ髑闆r
三、迭代器模式
經(jīng)過第二步我們基本已經(jīng)實(shí)現(xiàn)迭代器模式,最后我們?cè)俑牧家幌麓蛴〔藛?,并?duì)菜單進(jìn)行統(tǒng)一接口的管理。
定義一個(gè)Menu接口
public interface Menu { Iterator CreateIterator(); }
讓早餐晚餐都實(shí)現(xiàn)Menu接口,并封裝一個(gè)新的菜單打印
public class NewMenu { Menu breakFastMenu; Menu dinerMenu; public NewMenu(Menu breakFastMenu, Menu dinerMenu) { this.breakFastMenu = breakFastMenu; this.dinerMenu = dinerMenu; } public void PrintMenu() { Iterator breakFastIterator = breakFastMenu.CreateIterator(); Console.WriteLine("新菜單--------早餐"); PrintMenu(breakFastIterator); Console.WriteLine("新菜單--------晚餐"); Iterator dinerIterator = dinerMenu.CreateIterator(); PrintMenu(dinerIterator); } private void PrintMenu(Iterator iterator) { while (iterator.HasNext()) { //取得下一個(gè)項(xiàng) MenuItme menuItme = (MenuItme)iterator.Next(); Console.WriteLine(menuItme.Name); } } }
迭代器模式定義:
迭代器模式:提供一種方法順序訪問一個(gè)集合對(duì)象中的各個(gè)元素,而又不暴露其內(nèi)部的表示。
迭代器模式讓我們能游走于集合內(nèi)的每一個(gè)元素,而又不暴露其內(nèi)部的表示。
把游走的任務(wù)放在迭代器上,而不是集合上。這樣簡(jiǎn)化了集合的接口和實(shí)現(xiàn),也讓責(zé)任各得其所。
總結(jié)
到此這篇關(guān)于C#設(shè)計(jì)模式實(shí)現(xiàn)之迭代器模式的文章就介紹到這了,更多相關(guān)C#迭代器模式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#?計(jì)算DataTime的4種時(shí)間差的方法(相差天數(shù)、相差小時(shí)、相差分鐘、相差秒)
這篇文章主要介紹了C#?計(jì)算DataTime的4種時(shí)間差(相差天數(shù)、相差小時(shí)、相差分鐘、相差秒),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-05-05C# ManagementObjectSearcher操作window案例詳解
這篇文章主要介紹了C# ManagementObjectSearcher操作window案例詳解,本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08C#簡(jiǎn)單讀取主機(jī)上所有進(jìn)程的方法
這篇文章主要介紹了C#簡(jiǎn)單讀取主機(jī)上所有進(jìn)程的方法,涉及C#進(jìn)程的遍歷讀取操作相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2016-08-08WPF中鼠標(biāo)/鍵盤/拖拽事件以及用行為封裝事件詳解
這篇文章主要為大家詳細(xì)介紹了WPF中常用的鼠標(biāo)事件、鍵盤事件以及注意事項(xiàng),同時(shí)使用一個(gè)案例講解了拓展事件,感興趣的小伙伴可以了解一下2023-03-03C#操作SQLite數(shù)據(jù)庫方法小結(jié)
這篇文章介紹了C#操作SQLite數(shù)據(jù)庫的方法,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06C#實(shí)現(xiàn)文件操作(復(fù)制,移動(dòng),刪除)的方法詳解
File類提供了常見的文件操作函數(shù),包括復(fù)制、移動(dòng)、刪除、創(chuàng)建快捷方式等,本文將通過一些簡(jiǎn)單的示例為大家詳細(xì)講講具體的使用,希望對(duì)大家有所幫助2023-05-05