《設(shè)計模式》一書對于訪問者模式給出的定義為:表示一個作用于某對象結(jié)構(gòu)中的各元素的操作。它使你可以在不改變各元素的類的前提下定義作用于這些元素的新操作。從定義可以看出結(jié)構(gòu)對象是使用訪問者模式必須條件,而且這個結(jié)構(gòu)對象必須存在遍歷自身各個對象的方法。
設(shè)想一個場景,就是學(xué)校,學(xué)校里有老師和學(xué)生,老師和學(xué)生可以稱為兩種元素,我們可以對這些元素進行很多操作(注意,這些操作都是外部性質(zhì)的,不屬于元素本身,這個至關(guān)重要),比如評價,問卷調(diào)查,采訪和體檢等,如果我們把這些操作定義在元素層次,顯然不合理,一是這些操作不是元素對象的固有屬性和行為,而是一些外部操作,不符合面向?qū)ο蟮姆庋b和責(zé)任單一原則。如果把這些操作定義在學(xué)校這層,顯然也不合理,因為學(xué)校的責(zé)任只是對老師和學(xué)生進行管理,這些操作也不是學(xué)校的職責(zé)。既然不能定義在元素層和學(xué)校層,我們可以單獨定義一個層次結(jié)構(gòu)來實現(xiàn),但這里面有兩個問題,一是這些操作可能對不同的元素有不同的形式,二是這些操作還必須得到元素的許可,即元素可以接收你的訪問。上面的場景其實就是訪問者模式的典型應(yīng)用場景,下面訪問者的簡圖:
上面場景的實現(xiàn)代碼:
using System;
using System.Collections.Generic;
using System.Text;
namespace DesignModelStudy
{
public abstract class Person
{
public abstract void Accept(Person_Visitor VA);
public abstract int GetPersonType();
}
//Studeng對象.
class Student : Person
{
private int _id;
private string _name;
public override int GetPersonType()
{
return 1;
}
public Student(int ID, string Name)
{
this._name = Name;
this._id = ID;
}
public int ID
{
get
{
return this._id;
}
set
{
this._id = value;
}
}
public string Name
{
get
{
return this._name;
}
set
{
this._name = value;
}
}
public override void Accept(Person_Visitor VA)
{
System.Windows.Forms.MessageBox.Show(VA.Visit(this));
}
}
//Teacher對象.
class Teacher : Person
{
private int _id;
private string _name;
private int _age;
public Teacher(int ID, string Name,int Age)
{
this._name = Name;
this._id = ID;
this._age = Age;
}
public int ID
{
get
{
return this._id;
}
set
{
this._id = value;
}
}
public string Name
{
get
{
return this._name;
}
set
{
this._name = value;
}
}
public int Age
{
get
{
return this._age;
}
set
{
this._age = value;
}
}
public override void Accept(Person_Visitor VA)
{
System.Windows.Forms.MessageBox.Show(VA.Visit(this));
}
public override int GetPersonType()
{
return 2;
}
}
//人員管理類
class School
{
private System.Collections.ArrayList _students;
public School()
{
_students = new System.Collections.ArrayList();
}
public void Add(Person st)
{
if (this._students.IndexOf(st) < 0)
{
this._students.Add(st);
}
}
public void Del(Person st)
{
this._students.Remove(st);
}
public Person GetStudent(int index)
{
if (index >= 0 && index < this._students.Count)
{
return (Person)this._students[index];
}
return null;
}
public Person this[int index]
{
get
{
if (index >= 0 && index < this._students.Count)
{
return (Person)this._students[index];
}
return null;
}
}
public int Count
{
get
{
return this._students.Count;
}
}
}
public abstract class Person_Visitor
{
public abstract string Visit(Person p);
}
//對人員進行評價
public class EvaluateVisit : Person_Visitor
{
public override string Visit(Person p)
{
if (p is Student)
{
return "學(xué)生:" + ((Student)p).Name + " 評價" + " 結(jié)果:10";
}
else
{
return "老師:" + ((Teacher)p).Name + "" + " 年齡:" + ((Teacher)p).Age.ToString() + " 評價結(jié)果:30";
}
}
}
//對人員進行采訪
public class InterviewVisit : Person_Visitor
{
public override string Visit(Person p)
{
if (p is Student)
{
return "學(xué)生:" + ((Student)p).Name + " 已經(jīng)采訪" + " 結(jié)果:10";
}
else
{
return "老師:" + ((Teacher)p).Name + "已經(jīng)采訪" + " 年齡:" + ((Teacher)p).Age.ToString();
}
}
}
public class VisitorTest
{
private School _pMgr;
public VisitorTest()
{
_pMgr = new School();
}
public void CreateDatas()
{
Random rd = new Random();
for (int i = 0; i < 10; i++)
{
if ((i % 2) == 1)
{
this._pMgr.Add(new Student(i, "學(xué)生" + i.ToString()));
}
else
{
this._pMgr.Add(new Teacher(i, "老師" + i.ToString(), 30 + Convert.ToInt32(rd.NextDouble() * 100)));
}
}
}
public void Test()
{
EvaluateVisit ev = new EvaluateVisit();
for (int i=0;i<this._pMgr.Count;i++)
{
this._pMgr[i].Accept(ev);
}
}
}
}
總結(jié):
1)訪問者模式提供了一種將數(shù)據(jù)結(jié)構(gòu)和附加到該數(shù)據(jù)結(jié)構(gòu)的操作進行分離解耦的方法,當(dāng)然,要使用訪問者模式,有一個必要條件就是數(shù)據(jù)元素要比較多而且進行集合式管理。原因非常簡單,如果數(shù)據(jù)結(jié)構(gòu)的元素數(shù)目比較少,而且不能進行批處理(集合的好處就是可以進行批處理),利用訪問者模式就沒有什么優(yōu)勢。
2)訪問者模式適合于對那些元素數(shù)目多(而且能進行整體性管理,比如集合,組合,樹型結(jié)構(gòu)),需要進行附加操作(但操作多,變化大,不確定)處理的地方。
3)訪問者模式一般跟集合,組合模式一起使用會比較多。
4)特別注意,訪問者模式并不是為了將類的數(shù)據(jù)屬性和操作屬性分離。訪問者模式提供的是一種數(shù)據(jù)元素與附加操作之間進行協(xié)調(diào)管理的一種方式。
后記:現(xiàn)在的編程語言中采用這種模式的地方很多,比如對流操作中的stream和reader,writer,針對可枚舉對象的迭代和查詢等。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
