访问者模式(Visitor Pattern)
访问者模式的定义
表示一个作用于某对象结构中的各个元素的操作。它使你可以在不改变各个元素的类的前提下定义作用于这些元素的新操作。
访问者模式是用来封装一些施加于某种数据结构之上的操作。它使得可以在不改变元素本身的前提下增加作用于这些元素的新操作,访问者模式的目的是把操作从数据结构中分离出来。
访问者模式具体应用场景:
- 如果系统有比较稳定的数据结构,而又有易于变化的算法时,此时可以考虑使用访问者模式。因为访问者模式使得算法操作的添加比较容易。
- 如果一组类中,存在着相似的操作,为了避免出现大量重复的代码,可以考虑把重复的操作封装到访问者中。(当然也可以考虑使用抽象类了)
- 如果一个对象存在着一些与本身对象不相干,或关系比较弱的操作时,为了避免操作污染这个对象,则可以考虑把这些操作封装到访问者对象中。
- 访问者模式适用于数据结构相对未定的系统,它把数据结构和作用于结构上的操作之间的耦合解脱开,使得操作
集合可以相对自由地演化。
访问者模式具有以下优点:
- 访问者模式使得添加新的操作变得容易。如果一些操作依赖于一个复杂的结构对象的话,那么一般而言,添加新的操作会变得很复杂。而使用访问者模式,增加新的操作就意味着添加一个新的访问者类。因此,使得添加新的操作变得容易。
- 访问者模式使得有关的行为操作集中到一个访问者对象中,而不是分散到一个个的元素类中。这点类似与"中介者模式"。
- 访问者模式可以访问属于不同的等级结构的成员对象,而迭代只能访问属于同一个等级结构的成员对象。
访问者模式也有如下的缺点:
- 增加新的元素类变得困难。每增加一个新的元素意味着要在抽象访问者角色中增加一个新的抽象操作,并在每一个具体访问者类中添加相应的具体操作。
结构:
- 抽象访问者角色(Vistor):声明一个活多个访问操作,使得所有具体访问者必须实现的接口。
- 具体访问者角色(ConcreteVistor):实现抽象访问者角色中所有声明的接口。
- 抽象节点角色(Element):声明一个接受操作,接受一个访问者对象作为参数。
- 具体节点角色(ConcreteElement):实现抽象元素所规定的接受操作。
- 结构对象角色(ObjectStructure):节点的容器,可以包含多个不同类或接口的容器。可以遍历结构中的所有元素;如果需要,提供一个高层次的接口让访问者对象可以访问每一个元素;如果需要,可以设计成一个复合对象或者一个聚集,如列(List)或集合(Set)。
抽象元素基类:
/// <summary>
/// 抽象元素基类
/// </summary>
public abstract class Base_Element
{
/// <summary>
/// 访问者访问入口
/// </summary>
/// <param name="vistor"></param>
public abstract void Accept(I_Vistor vistor);
/// <summary>
/// 打印方法
/// </summary>
public abstract void Print(string str);
}
具体元素:
//具体元素1
public class Element1 : Base_Element
{
public string name = "元素1";
public override void Accept(I_Vistor vistor)
{
vistor.Visit(this);
}
public override void Print(string str)
{
Debug.Log("我是" + str);
}
}
//具体元素2
public class Element2 : Base_Element
{
public string name = "元素2";
public override void Accept(I_Vistor vistor)
{
vistor.Visit(this);
}
public override void Print(string str)
{
Debug.Log("我是" + str);
}
}
抽象访问者:
/// <summary>
/// 抽象访问者
/// </summary>
public interface I_Vistor
{
void Visit(Element1 a);
void Visit(Element2 a);
}
具体访问者:
/// <summary>
/// 具体访问者
/// </summary>
public class Vistor : I_Vistor
{
public void Visit(Element1 a)
{
a.Print(a.name);
}
public void Visit(Element2 b)
{
b.Print(b.name);
}
}
对象结构:
/// <summary>
/// 结构对象角色
/// </summary>
class ObjStructure
{
//对象池
private ArrayList elements = new ArrayList();
//添加对象
public void Add(Base_Element element)
{
elements.Add(element);
}
//删除对象
public void Remove(Base_Element element)
{
elements.Remove(element);
}
//访问全部对象
public void Accept(I_Vistor vistor)
{
foreach (Base_Element e in elements)
e.Accept(vistor);
}
}
运行测试:
void Start()
{
Base_Element E1 = new Element1();//新建元素1
Base_Element E2 = new Element2();//新建元素2
E1.Accept(new Vistor());//访问者访问元素1
E2.Accept(new Vistor());//访问者访问元素2
ObjStructure obj = new ObjStructure();//新建结构对象
obj.Add(new Element1());//添加元素
obj.Add(new Element1());
obj.Add(new Element2());
obj.Add(new Element2());
obj.Accept(new Vistor());//访问者访问所有元素
}
结果: