目录
访问者模式
引言
定义
模式结构图
实例
实例说明
实例类图
代码实现
模式扩展
倾斜的“开闭原则”
总结
模式优点
模式缺点
访问者模式是一种较为复杂的行为型设计模式,它包含访问者和被访问元素俩个主要组成部分,这些被访问的元素具有不同的类型,且不同的访问者可以对其进行不同的访问操作。访问者模式使得用户可以在不修改现有系统的情况下扩展系统的功能,为这些不同类型的元素增加新的操作。
英文定义:“Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changeing the classes of the elements on which it operates.”。
中文定义:表示一个作用于某对象结构中的各个元素的操作,它使我们可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
访问者模式重要等级★☆☆☆☆ 中介者模式难度等级★★★★☆
访问者模式包含如下角色:
1)Visitor抽象访问者类:抽象访问者类需要定义对每一个具体元素的访问操作。
2)ConcreteVisitor 具体访问者类
3)Element抽象元素:提供一个以抽象访问者为参数的访问方法。
4)ConcreteElement 具体元素类
5) ObjectStruture 对象结构:用于存放元素对象。
顾客在超市中将选择的商品,如苹果,图书等放在购物车中,然后到收银员处付款。在购物过程中,顾客需要对这些商品进行访问,之后收银员计算价格的时候也要对商品进行访问。使用访问者模式来设计该购物过程。
抽象商品类(元素类)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
interface MarketProduct
{
void Accept(Visitor v);
}
具体商品
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
class Apple : MarketProduct
{
public void Accept(Visitor v)
{
v.Visit(this);
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
class Hat : MarketProduct
{
public void Accept(Visitor v)
{
v.Visit(this);
}
}
抽象访问者
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
interface Visitor
{
void Visit(Apple a);
void Visit(Hat h);
}
具体访问者
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
class Saler : Visitor
{
public void Visit(Hat h)
{
Console.WriteLine("销售员访问帽子");
}
public void Visit(Apple a)
{
Console.WriteLine("销售员访问苹果");
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
class Customer : Visitor
{
public void Visit(Hat h)
{
Console.WriteLine("客户访问帽子");
}
public void Visit(Apple a)
{
Console.WriteLine("客户访问苹果");
}
}
购物车类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
class BuyBasket
{
private List products = new List();
public void Visit(Visitor v)
{
foreach(MarketProduct p in products)
{
p.Accept(v);
}
}
public void Add(MarketProduct p)
{
products.Add(p);
}
}
测试代码
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading;
class Program
{
static void Main(string[] args)
{
BuyBasket buyBasket = new BuyBasket();
Saler saler = new Saler();
Customer customer = new Customer();
buyBasket.Add(new Apple());
buyBasket.Add(new Hat());
buyBasket.Visit(saler);
buyBasket.Visit(customer);
Console.ReadKey();
}
}
运行结果
与抽象工厂模式一样,访问者模式对“开闭原则”的支持也具有倾斜性,在访问者模式中,增加一个新的访问者,无需修改系统源码,满足“开闭原则”。但是新增一个被访问的元素,需要在抽象访问者以及每个访问者中新增对新元素的访问方法,对系统进行较大的改动,这将违背“开闭原则”。
1)使得增加新的访问操作变得容易。
2)将有关元素对象的访问行为集中到一个访问者对象中,而不是分散到一个个的元素类中。类的职责更加清晰,有利于对象结构中元素对象的复用,相同的对象结构可以供多个不同的访问者访问。
3)可以跨过类的等级结构访问属于不同的等级结构的元素类。
4)让用户能在不修改现有类层次结构的情况下,定义该类层次结构的新操作。
1)增加新的元素类很困难。
2)破坏了封装。访问者模式要求访问者对象访问并调用每一个元素对象的操作,这意味着元素对象有时候必须暴漏一些自己的内部操作和内部状态,否则无法供访问者访问。