访问者模式

一、完成者信息:

姓名:王璐

学号:07770231

 

二、模式信息

模式名称:访问者模式

生活场景:假如以前食堂的食品和饮料一直都是一个价位,没有变动。这学期开学,由于工商局调节价位,导致普遍商品都涨价了,所以学校食堂里,菜价和饮料都涨价了。

终极目标:实现能够对所有的情况进行访问,通知发生变化。

 

不使用访问者模式

  1.  不假思索的思路:我们去吃饭,首先看菜单,来选择食物,用现在的菜单跟以前的菜单相对比,价位之间的变化。

类结构图: 

 

 

代码实现:

代码
1)菜单
//菜单
public abstract class Menu
{
public abstract void OldPrice(); //以前价格

public abstract void NowPrice(); //涨价之后现在价格
}
2)饮料
//饮料类
public class Drink:Menu
{
public override void OldPrice()
{
Console.WriteLine(
"康师傅绿茶以前食堂卖2.5元/瓶!");
}

public override void NowPrice()
{
Console.WriteLine(
"这学期开学,康师傅绿茶在原来基础上涨到3.0元/瓶!");
}
}
3)食品
//食品类
public class Food:Menu
{
public override void OldPrice()
{
Console.WriteLine(
"食堂里原来每份菜5.0元/份!");
}

public override void NowPrice()
{
Console.WriteLine(
"这学期开学,每份菜涨到6.0元/份!");
}
}
4)主函数
class Program
{
static void Main()
{
Drink drink
= new Drink();
drink.OldPrice();
drink.NowPrice();

Console.WriteLine(
" ");

Food food
= new Food();
food.OldPrice();
food.NowPrice();
Console.Read();
}
}

 

 

运行结果:

存在问题:

在软件构建过程中,由于需求的改变,某些类层次结构中常常需要增加新的行为(方法),如果直接在基类中做这样的改变,将会给子类带来很繁重的变更负担,甚至破坏原有设计。

2. 归纳阶段:使用访问者模式

当前目标:增加一个抽象访问者与实现访问者。以实现价格的调整,上涨或者下降;加一个聚合类以实现菜单种类的变更,增加或减少。

类结构图:

 

代码实现:

代码
1) 菜单类
饮料和食品都得接受访问者菜单的通知
//菜单
public abstract class Menu
{
public abstract void OldPrice();

//这学期开学,食堂饭价涨价
public abstract void Accept(IndustryVisitor Visitor);
}
2)饮料实现
//饮料
public class Drink:Menu
{
public override void OldPrice()
{
Console.WriteLine(
"康师傅绿茶以前食堂卖2.5元/瓶!");
}

public override void Accept(IndustryVisitor Visitor)
{
Visitor.Visit(
this);
Console.WriteLine(
" ");
}

}
3) 食品实现
//食品
public class Food:Menu
{
public override void OldPrice()
{
Console.WriteLine(
"食堂里原来每份菜5.0元/份!"); ;
}

public override void Accept(IndustryVisitor Visitor)
{
Visitor.Visit(
this);
}
}
4)聚合类
用于确定价格变动的部门,可分配的:食品和饮料有多种,其中两种都在涨价
//工商管理部门
public class IndustryMangement
{
IList
<Menu> _list = new List<Menu>();

public void Add(Menu menu)
{
_list.Add(menu);
}
public void Detach(Menu menu)
{
_list.Remove(menu);
}
public void Accept(IndustryVisitor visitor)
{
foreach (Menu m in _list)
{
m.Accept(visitor);
}
}
}
5)抽象访问者
价格在变,所以不同时期,价格不同,价格为访问者。
//访问者抽象
public abstract class IndustryVisitor
{
public abstract void Visit(Drink drink);
public abstract void Visit(Food food);

internal void Visit()
{
throw new NotImplementedException();
}
}
6)访问者实现
//新学期,饭价上涨
//目的通知涨价细节
public class New_SchoolTerm:IndustryVisitor
{
public override void Visit(Drink drink)
{
drink.OldPrice();
Console.WriteLine(
"这学期开学,康师傅绿茶在原来基础上涨到3.0元/瓶!");
}

public override void Visit(Food food)
{
food.OldPrice();
Console.WriteLine(
"这学期开学,每份菜涨到6.0元/份!");
}
}
7)主函数
class Program
{
static void Main()
{
IndustryMangement mangement
= new IndustryMangement();

mangement.Add(
new Drink());
mangement.Add(
new Food());

mangement.Accept(
new New_SchoolTerm());
Console.Read();
}
}

3.   验证阶段

当前目标:在上面的基础上增加一个水果类。

类结构图:

 

 代码实现:

代码
1)菜单类
饮料和食品都得接受访问者菜单的通知
//菜单
public abstract class Menu
{
public abstract void OldPrice();

//这学期开学,食堂饭价涨价
public abstract void Accept(IndustryVisitor Visitor);
}
2)饮料实现
//饮料
public class Drink:Menu
{
public override void OldPrice()
{
Console.WriteLine(
"康师傅绿茶以前食堂卖2.5元/瓶!");
}

public override void Accept(IndustryVisitor Visitor)
{
Visitor.Visit(
this);
Console.WriteLine(
" ");
}

}
3) 食品实现
//食品
public class Food:Menu
{
public override void OldPrice()
{
Console.WriteLine(
"食堂里原来每份菜5.0元/份!"); ;
}

public override void Accept(IndustryVisitor Visitor)
{
Visitor.Visit(
this);
Console.WriteLine(
" ");
}
}
4) 水果实现
//水果实现
public class Fruit:Menu
{
public override void OldPrice()
{
Console.WriteLine(
"苹果在调价之前是2.5元/斤!");
}

public override void Accept(IndustryVisitor Visitor)
{
Visitor.Visit(
this);
Console.WriteLine(
" ");
}
}
5)聚合类
用于确定价格变动的部门,可分配的:食品和饮料有多种,其中两种都在涨价
//工商管理部门
public class IndustryMangement
{
IList
<Menu> _list = new List<Menu>();

public void Add(Menu menu)
{
_list.Add(menu);
}
public void Detach(Menu menu)
{
_list.Remove(menu);
}
public void Accept(IndustryVisitor visitor)
{
foreach (Menu m in _list)
{
m.Accept(visitor);
}
}
}
6)抽象访问者
价格在变,所以不同时期,价格不同,价格为访问者。
//访问者抽象
public abstract class IndustryVisitor
{
public abstract void Visit(Drink drink);
public abstract void Visit(Food food);
public abstract void Visit(Fruit fruit);

internal void Visit()
{
throw new NotImplementedException();
}
}
7)访问者实现
//新学期,饭价上涨
//目的通知涨价细节
public class New_SchoolTerm:IndustryVisitor
{
public override void Visit(Drink drink)
{
drink.OldPrice();
Console.WriteLine(
"这学期开学,康师傅绿茶在原来基础上涨到3.0元/瓶!");
}

public override void Visit(Food food)
{
food.OldPrice();
Console.WriteLine(
"这学期开学,每份菜涨到6.0元/份!");
}
public override void Visit(Fruit fruit)
{
fruit.OldPrice();
Console.WriteLine(
"调价之后苹果3.5元/斤!");
}
}
8)主函数
class Program
{
static void Main()
{
IndustryMangement mangement
= new IndustryMangement();

mangement.Add(
new Drink());
mangement.Add(
new Food());
mangement.Add(
new Fruit());

mangement.Accept(
new New_SchoolTerm());
Console.Read();
}
}

 

 

 

运行结果:

 

设计体会:

1.1.Visitor模式通过所谓双重分发(double dispatch)来实现在不更改Element类层次结构的前提下,在运行时透明地为类层次结构上的各个类动态添加新的操作。

2.所谓双重分发却Visotor模式中间包括了两个多态分发(注意其中的多态机制);第一个为accept方法的多态辨析;第二个为visitor方法的多态辨析。

 4.    抽象阶段

概念:访问者模式的目的是封装一些施加于某种数据结构元素之上的操作。一旦这些操作需要修改的话,接受这个操作的数据结构则可以保持不变。

    访问者模式适用于数据结构相对未定的系统,它把数据结构和作用于结构上的操作之间的耦合解脱开,使得操作集合可以相对自由地演化。数据结构的每一个节点都可以接受一个访问者的调用,此节点向访问者对象传入节点对象,而访问者对象则反过来执行节点对象的操作。这样的过程叫做"双重分派"。节点调用访问者,将它自己传入,访问者则将某算法针对此节点执行。

Visitor抽象访问者:声明了一个或者多个访问操作,形成所有的具体元素角色必须实现的接口。

ConcreteVisitor具体访问者:实现抽象访问者角色所声明的接口,也就是抽象访问者所声明的各个访问操作。

Element抽象节点:声明一个接受操作,接受一个访问者对象作为一个参量。

ConcreteElement抽象具体节点:实现了抽象元素所规定的接受操作。

ObjectStructure对象结构类:有如下的一些责任,可以遍历结构中的所有元素;如果需要,提供一个高层次的接口让访问者对象可以访问每一个元素;如果需要,可以设计成一个复合对象或者一个聚集,如列(List)或集合(Set)。

 

访问者模式的适用性:

1.一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作。

2.需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作"污染"这些对象的类。Visitor使得你可以将相关的操作集中起来定义在一个类中。当该对象结构被很多应用共享时,用Visitor模式让每个应用仅包含需要用到的操作。

3.定义对象结构的类很少改变,但经常需要在结构上定义新的操作。改变对象结构类需要重定义对所有访问者的接口,这可能需要很大的代价。如果对象结构类经常改变,那么可能还是在这些类中定义这些操作较好。

posted @ 2010-12-09 13:07  天津城建学院软件工程  阅读(598)  评论(0编辑  收藏  举报