一、引言

          ?? 今天我們開始講“行為型”設(shè)計(jì)模式的第九個(gè)模式,該模式是【訪問(wèn)者模式】,英文名稱是:Visitor
          Pattern。如果按老規(guī)矩,先從名稱上來(lái)看看這個(gè)模式,我根本不能獲得任何對(duì)理解該模式有用的信息,而且這個(gè)模式在我們的編碼生活中使用的并不是很多。該模式的意圖定義很抽象,第一次看了這個(gè)定義其實(shí)和沒(méi)看沒(méi)有什么區(qū)別,一頭霧水,為了讓大家更好的理解該模式的初衷,我們舉個(gè)例子來(lái)說(shuō)明模式。比如:當(dāng)我們?yōu)榱私鉀Q一個(gè)新的軟件需求的時(shí)候,經(jīng)過(guò)多個(gè)日以繼夜的努力,最終通過(guò)一個(gè)完美(自己認(rèn)為的)的軟件設(shè)計(jì)解決了客戶提出的新的需求,而且這個(gè)設(shè)計(jì)有完美的類層次結(jié)構(gòu),并且是符合OO的設(shè)計(jì)原則的,我們很開心,對(duì)自己設(shè)計(jì)的東西很有成就感。又過(guò)了一段時(shí)間,客戶突然又有了一個(gè)新的需求,需要為現(xiàn)有的類層次結(jié)構(gòu)里面的類增加一個(gè)新的操作(其實(shí)就是一個(gè)方法),怎么辦?好辦,在面向OO設(shè)計(jì)模式中有一個(gè)模式就是為了解決這個(gè)問(wèn)題的,那就是“訪問(wèn)者模式”,可以為現(xiàn)有的類層次結(jié)構(gòu)中的類輕松增加新的操作,我們繼續(xù)吧,好好的了解一下該模式。

          二、訪問(wèn)者模式的詳細(xì)介紹

          2.1、動(dòng)機(jī)(Motivate)

          ??
          在軟件構(gòu)建過(guò)程中,由于需求的改變,某些類層次結(jié)構(gòu)中常常需要增加新的行為(方法),如果直接在基類中做這樣的更改,將會(huì)給子類帶來(lái)很繁重的變更負(fù)擔(dān),甚至破壞原有設(shè)計(jì)。如何在不更改類層次結(jié)構(gòu)的前提下,在運(yùn)行時(shí)根據(jù)需要透明地為類層次結(jié)構(gòu)上的各個(gè)類動(dòng)態(tài)添加新的操作,從而避免上述問(wèn)題?

          2.2、意圖(Intent)

          ??
          表示一個(gè)作用于某對(duì)象結(jié)構(gòu)中的各個(gè)元素的操作。它可以在不改變各元素的類的前提下定義作用于這些元素的新的操作?!     ???????????????????????????????
          ——《設(shè)計(jì)模式》GoF

          2.3、結(jié)構(gòu)圖(Structure)

          ????

          2.4、模式的組成
          ?? ?
          ??? 可以看出,在訪問(wèn)者模式的結(jié)構(gòu)圖有以下角色:

          ??? (1)、抽象訪問(wèn)者角色(Vistor):
          聲明一個(gè)包括多個(gè)訪問(wèn)操作,多個(gè)操作針對(duì)多個(gè)具體節(jié)點(diǎn)角色(可以說(shuō)有多少個(gè)具體節(jié)點(diǎn)角色就有多少訪問(wèn)操作),使得所有具體訪問(wèn)者必須實(shí)現(xiàn)的接口。

          ??? (2)、具體訪問(wèn)者角色(ConcreteVistor):實(shí)現(xiàn)抽象訪問(wèn)者角色中所有聲明的接口,也可以說(shuō)是實(shí)現(xiàn)對(duì)每個(gè)具體節(jié)點(diǎn)角色的新的操作。

          ??? (3)、抽象節(jié)點(diǎn)角色(Element):聲明一個(gè)接受操作,接受一個(gè)訪問(wèn)者對(duì)象作為參數(shù),如果有其他參數(shù),可以在這個(gè)“接受操作”里在定義相關(guān)的參數(shù)。

          ??? (4)、具體節(jié)點(diǎn)角色(ConcreteElement):實(shí)現(xiàn)抽象元素所規(guī)定的接受操作。

          ??? (5)、結(jié)構(gòu)對(duì)象角色(ObjectStructure):節(jié)點(diǎn)的容器,可以包含多個(gè)不同類或接口的容器。

          2.5、訪問(wèn)者模式的代碼實(shí)現(xiàn)

          ???
          訪問(wèn)者這個(gè)模式在我們現(xiàn)實(shí)的編碼生活中使用的并不是很多,我就直接貼代碼,讓大家看代碼的結(jié)構(gòu)吧。今天給大家兩個(gè)代碼實(shí)例,自己慢慢體會(huì)訪問(wèn)者吧。實(shí)現(xiàn)代碼如下:
          1 namespace Vistor 2 { 3 //抽象圖形定義---相當(dāng)于“抽象節(jié)點(diǎn)角色”Element 4 public abstract
          class Shape 5 { 6 //畫圖形 7 public abstract void Draw(); 8 //外界注入具體訪問(wèn)者 9
          public abstract void Accept(ShapeVisitor visitor); 10 } 11 12 //抽象訪問(wèn)者
          Visitor 13 public abstract class ShapeVisitor 14 { 15 public abstract void
          Visit(Rectangle shape); 16 17 public abstract void Visit(Circle shape); 18 19
          public abstract void Visit(Line shape); 20 21 //
          這里有一點(diǎn)要說(shuō):Visit方法的參數(shù)可以寫成Shape嗎?就是這樣 Visit(Shape
          shape),當(dāng)然可以,但是ShapeVisitor子類Visit方法就需要判斷當(dāng)前的Shape是什么類型,是Rectangle類型,是Circle類型,或者是Line類型。
          22 } 23 24 //具體訪問(wèn)者 ConcreteVisitor 25 public sealed class CustomVisitor :
          ShapeVisitor 26 { 27 //針對(duì)Rectangle對(duì)象 28 public override void Visit(Rectangle
          shape) 29 { 30 Console.WriteLine("針對(duì)Rectangle新的操作!"); 31 } 32 //針對(duì)Circle對(duì)象
          33 public override void Visit(Circle shape) 34 { 35 Console.WriteLine("
          針對(duì)Circle新的操作!"); 36 } 37 //針對(duì)Line對(duì)象 38 public override void Visit(Line
          shape) 39 { 40 Console.WriteLine("針對(duì)Line新的操作!"); 41 } 42 } 43 44 //
          矩形----相當(dāng)于“具體節(jié)點(diǎn)角色” ConcreteElement 45 public sealed class Rectangle : Shape 46
          { 47 public override void Draw() 48 { 49 Console.WriteLine("矩形我已經(jīng)畫好!"); 50
          } 51 52 public override void Accept(ShapeVisitor visitor) 53 { 54
          visitor.Visit(this); 55 } 56 } 57 58 //圓形---相當(dāng)于“具體節(jié)點(diǎn)角色”ConcreteElement 59
          public sealed class Circle : Shape 60 { 61 public override void Draw() 62 {
          63 Console.WriteLine("圓形我已經(jīng)畫好!"); 64 } 65 66 public override void
          Accept(ShapeVisitor visitor) 67 { 68 visitor.Visit(this); 69 } 70 } 71
          72 //直線---相當(dāng)于“具體節(jié)點(diǎn)角色” ConcreteElement 73 public sealed class Line : Shape 74
          { 75 public override void Draw() 76 { 77 Console.WriteLine("直線我已經(jīng)畫好!"); 78
          } 79 80 public override void Accept(ShapeVisitor visitor) 81 { 82
          visitor.Visit(this); 83 } 84 } 85 86 //結(jié)構(gòu)對(duì)象角色 87 internal class
          AppStructure 88 { 89 private ShapeVisitor _visitor; 90 91 public
          AppStructure(ShapeVisitor visitor) 92 { 93 this._visitor = visitor; 94 } 95
          96 public void Process(Shape shape) 97 { 98 shape.Accept(_visitor); 99 }
          100 } 101 102 class Program 103 { 104 static void Main(string[] args) 105 {
          106 //如果想執(zhí)行新增加的操作 107 ShapeVisitor visitor = new CustomVisitor(); 108
          AppStructure app =new AppStructure(visitor); 109 110 Shape shape = new
          Rectangle();111 shape.Draw();//執(zhí)行自己的操作 112 app.Process(shape);//執(zhí)行新的操作 113 114
          115 shape = new Circle(); 116 shape.Draw();//執(zhí)行自己的操作 117 app.Process(shape);//
          執(zhí)行新的操作 118 119 120 shape = new Line(); 121 shape.Draw();//執(zhí)行自己的操作 122
          app.Process(shape);//執(zhí)行新的操作 123 124 125 Console.ReadLine(); 126 } 127 } 128 }
          這是訪問(wèn)者模式第二種代碼實(shí)例:
          1 namespace Visitor 2 { 3 //抽象訪問(wèn)者角色 Visitor 4 public abstract class Visitor
          5 { 6 public abstract void PutTelevision(Television tv); 7 8 public
          abstract void PutComputer(Computer comp); 9 } 10 11 //具體訪問(wèn)者角色
          ConcreteVisitor 12 public sealed class SizeVisitor : Visitor 13 { 14 public
          override void PutTelevision(Television tv) 15 { 16 Console.WriteLine("
          按商品大小{0}排放", tv.Size); 17 } 18 19 public override void PutComputer(Computer
          comp) 20 { 21 Console.WriteLine("按商品大小{0}排放", comp.Size); 22 } 23 } 24
          25 //具體訪問(wèn)者角色 ConcreteVisitor 26 public sealed class StateVisitor : Visitor 27
          { 28 public override void PutTelevision(Television tv) 29 { 30
          Console.WriteLine("按商品新舊值{0}排放", tv.State); 31 } 32 33 public override void
          PutComputer(Computer comp) 34 { 35 Console.WriteLine("按商品新舊值{0}排放",
          comp.State); 36 } 37 } 38 39 //抽象節(jié)點(diǎn)角色 Element 40 public abstract class
          Goods 41 { 42 public abstract void Operate(Visitor visitor); 43 44 private
          int nSize; 45 public int Size 46 { 47 get { return nSize; } 48 set { nSize
          = value; } 49 } 50 51 private int nState; 52 public int State 53 { 54
          get { return nState; } 55 set { nState = value; } 56 } 57 } 58 59 //
          具體節(jié)點(diǎn)角色 ConcreteElement 60 public sealed class Television : Goods 61 { 62
          public override void Operate(Visitor visitor) 63 { 64 visitor.PutTelevision(
          this); 65 } 66 } 67 68 //具體節(jié)點(diǎn)角色 ConcreteElement 69 public sealed class
          Computer : Goods 70 { 71 public override void Operate(Visitor visitor) 72 {
          73 visitor.PutComputer(this); 74 } 75 } 76 77 //結(jié)構(gòu)對(duì)象角色 78 public sealed
          class StoragePlatform 79 { 80 private IList<Goods> list = new List<Goods>();
          81 82 public void Attach(Goods element) 83 { 84 list.Add(element); 85 }
          86 87 public void Detach(Goods element) 88 { 89 list.Remove(element); 90
          } 91 92 public void Operate(Visitor visitor) 93 { 94 foreach (Goods g in
          list) 95 { 96 g.Operate(visitor); 97 } 98 } 99 } 100 101 class Program
          102 { 103 static void Main(string[] args) 104 { 105 StoragePlatform platform =
          new StoragePlatform(); 106 platform.Attach(new Television()); 107
          platform.Attach(new Computer()); 108 109 SizeVisitor sizeVisitor = new
          SizeVisitor();110 StateVisitor stateVisitor = new StateVisitor(); 111 112
          platform.Operate(sizeVisitor);113 platform.Operate(stateVisitor); 114 115
          Console.Read();116 } 117 } 118 }

          三、訪問(wèn)者模式的實(shí)現(xiàn)要點(diǎn):

          ??? Visitor模式通過(guò)所謂雙重分發(fā)(double
          dispatch)來(lái)實(shí)現(xiàn)在不更改Element類層次結(jié)構(gòu)的前提下,在運(yùn)行時(shí)透明地為類層次結(jié)構(gòu)上的各個(gè)類動(dòng)態(tài)添加新的操作。所謂雙重分發(fā)即Visitor模式中間包括了兩個(gè)多態(tài)分發(fā)(注意其中的多態(tài)機(jī)制):第一個(gè)為accept方法的多態(tài)辨析;第二個(gè)為visit方法的多態(tài)辨析。


            設(shè)計(jì)模式其實(shí)是一種堵漏洞的方式,但是沒(méi)有一種設(shè)計(jì)模式能夠堵完所有的漏洞,即使是組合各種設(shè)計(jì)模式也是一樣。每個(gè)設(shè)計(jì)模式都有漏洞,都有它們解決不了的情況或者變化。每一種設(shè)計(jì)模式都假定了某種變化,也假定了某種不變化。Visitor模式假定的就是操作變化,而Element類層次結(jié)構(gòu)穩(wěn)定。

          ??? (1)、訪問(wèn)者模式的主要優(yōu)點(diǎn)有:

          ???????
          1】、訪問(wèn)者模式使得添加新的操作變得容易。如果一些操作依賴于一個(gè)復(fù)雜的結(jié)構(gòu)對(duì)象的話,那么一般而言,添加新的操作會(huì)變得很復(fù)雜。而使用訪問(wèn)者模式,增加新的操作就意味著添加一個(gè)新的訪問(wèn)者類。因此,使得添加新的操作變得容易。

          ??????? 2】、訪問(wèn)者模式使得有關(guān)的行為操作集中到一個(gè)訪問(wèn)者對(duì)象中,而不是分散到一個(gè)個(gè)的元素類中。這點(diǎn)類似與”中介者模式”。

          ??????? 3】、訪問(wèn)者模式可以訪問(wèn)屬于不同的等級(jí)結(jié)構(gòu)的成員對(duì)象,而迭代只能訪問(wèn)屬于同一個(gè)等級(jí)結(jié)構(gòu)的成員對(duì)象。

           (2)、訪問(wèn)者模式的主要缺點(diǎn)有:

          ???????
          1】、增加新的元素類變得困難。每增加一個(gè)新的元素意味著要在抽象訪問(wèn)者角色中增加一個(gè)新的抽象操作,并在每一個(gè)具體訪問(wèn)者類中添加相應(yīng)的具體操作。具體來(lái)說(shuō),Visitor模式的最大缺點(diǎn)在于擴(kuò)展類層次結(jié)構(gòu)(增添新的Element子類),會(huì)導(dǎo)致Visitor類的改變。因此Visitor模式適用于“Element類層次結(jié)構(gòu)穩(wěn)定,而其中的操作卻經(jīng)常面臨頻繁改動(dòng)”。

          ??? (3)、在下面的情況下可以考慮使用訪問(wèn)者模式:

          ??????? 1】、如果系統(tǒng)有比較穩(wěn)定的數(shù)據(jù)結(jié)構(gòu),而又有易于變化的算法時(shí),此時(shí)可以考慮使用訪問(wèn)者模式。因?yàn)樵L問(wèn)者模式使得算法操作的添加比較容易。

          ??????? 2】、如果一組類中,存在著相似的操作,為了避免出現(xiàn)大量重復(fù)的代碼,可以考慮把重復(fù)的操作封裝到訪問(wèn)者中。(當(dāng)然也可以考慮使用抽象類了)

          ??????? 3】、如果一個(gè)對(duì)象存在著一些與本身對(duì)象不相干,或關(guān)系比較弱的操作時(shí),為了避免操作污染這個(gè)對(duì)象,則可以考慮把這些操作封裝到訪問(wèn)者對(duì)象中。


          四、.NET 訪問(wèn)者模式的實(shí)現(xiàn)

          ????
          在現(xiàn)在的Net框架里面,如果要想給現(xiàn)有的類增加新的方法,有了新的方式,那就是“擴(kuò)展方法”,使用起來(lái)和實(shí)例方法是一樣一樣的,而且在Net框架里面,微軟自己也寫了很多的擴(kuò)展方法給我們使用。我目前還沒(méi)有學(xué)習(xí)到Net的框架類庫(kù)里面有“訪問(wèn)者模式”實(shí)現(xiàn),看來(lái)自己還需努力,革命尚未成功啊。

          五、總結(jié)

          ???
          訪問(wèn)者模式寫完了,這個(gè)模式剛開始理解起來(lái)還是挺麻煩的,但是,如果我們多看幾個(gè)實(shí)例代碼,完全掌握也不是問(wèn)題。隨著C#語(yǔ)言的發(fā)展,設(shè)計(jì)模式里面的很多東西,我們可以通過(guò)C#語(yǔ)言的一些特性做更好的替代。我們寫設(shè)計(jì)模式剛開始要慢慢來(lái),一步一步的照貓畫虎的來(lái)寫代碼,等我們熟練掌握了模式的核心意思,我們就要寫符合C#風(fēng)格和特性的模式代碼了,或者說(shuō)我們要用C#來(lái)寫設(shè)計(jì)模式了,寫出來(lái)的代碼會(huì)更棒。

          友情鏈接
          ioDraw流程圖
          API參考文檔
          OK工具箱
          云服務(wù)器優(yōu)惠
          阿里云優(yōu)惠券
          騰訊云優(yōu)惠券
          京東云優(yōu)惠券
          站點(diǎn)信息
          問(wèn)題反饋
          郵箱:[email protected]
          QQ群:637538335
          關(guān)注微信

                亚洲无码视频在线 | 亚洲日本无码 | www.艹b | 黄色免费看视频 | 黄色毛片网站 |