访问者模式

一、完成者信息:

姓名:王璐

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

转载于:https://www.cnblogs.com/tjcjxy/archive/2010/12/09/1901132.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值