模式实例之——访问者实例

简介: 场景:长途汽车票、火车票价格调整   描述:春运开始了,人流高峰期,打工的人群要回家过年了,票价要涨了!   1、抽象访问者(Visitor,程序中为:NotifyVisitor)角色:声明了一个或者多个访问操作,形成所有的具体元素角色必须实现的接口。

场景:长途汽车票、火车票价格调整

 

描述:春运开始了,人流高峰期,打工的人群要回家过年了,票价要涨了!

 

1、抽象访问者(Visitor,程序中为:NotifyVisitor)角色:声明了一个或者多个访问操作,形成所有的具体元素角色必须实现的接口。

2、具体访问者(ConcreteVisitor,程序中为各个期间的票价浮动情况)角色:实现抽象访问者角色所声明的接口,也就是抽象访问者所声明的各个访问操作。

3、抽象节点(Element,程序中的交通工具基类)角色:声明一个接受操作,接受一个访问者对象作为一个参量。

4、具体节点(ConcreteElement,程序中的各类交通工具)角色:实现了抽象元素所规定的接受操作。

5、结构对象(ObiectStructure,程序中的交通管理部门)角色:有如下的一些责任,可以遍历结构中的所有元素;如果需要,提供一个高层次的接口让访问者对象可以访问每一个元素;如果需要,可以设计成一个复合对象或者一个聚集,如列(List)或集合(Set)。 

 

在软件构建过程中,由于需求的改变,某些类层次结构中常常需要增加新的行为(方法),如果直接在基类中做这样的改变,将会给子类带来很繁重的变更负担,甚至破坏原有设计。
如何在不更改类层次结构的前提下,在运行时根据需要透明的为类层次结构上的各个类动态添加新的操作,从而避免上述问题?

标识一个作用于某对象结构中的各元素的操作。它可以在不改变各元素的类的前提下定义作用于这些元素的新的操作。

 

实现1:在不使用访问者的时候

(一)交通工具标准

//交通工具

    public abstract class Vehicle

    {

        public abstract void ShowPrice();

 

        //过年涨价

        public abstract void PriceFloatup();

    }

(二)长途汽车与火车

//bus

    public class Bus : Vehicle

    {

        public override void ShowPrice()

        {

            Console.WriteLine("长途汽车石家庄到邢台50");

        }

        public override void PriceFloatup()

        {

            Console.WriteLine("春运开始了,汽车票在原价的基础上,上浮20%");

        }

    }

 

    //train

    public class Train : Vehicle

    {

        public override void ShowPrice()

        {

            Console.WriteLine("火车石家庄到邢台40");

        }

 

        public override void PriceFloatup()

        {

            Console.WriteLine("春运开始了,火车票在原价的基础上,上浮15%");

        }

    }

(三)测试

Bus bus = new Bus();

bus.ShowPrice();

bus.PriceFloatup();

 

Train train = new Train();

train.ShowPrice();

train.PriceFloatup();

 

结果:

长途汽车石家庄到邢台50

春运开始了,汽车票在原价的基础上,上浮20%

火车石家庄到邢台40

春运开始了,火车票在原价的基础上,上浮15%

(四)特殊的日子,涨价

国庆期间,票价也要涨!

现在要在长途与火车中添加新的涨价通知。那么在基类中添加接口:

//国庆涨价

        public abstract void PriceNationdayFloatup();

在两个实现中添加实现:

public override void PriceNationdayFloatup()

        {

            Console.WriteLine("国庆期间,汽车票在原价的基础上,上浮5%");

        }

……

public override void PriceNationdayFloatup()

        {

            Console.WriteLine("国庆期间,火车票在原价的基础上,上浮3%");

}

(五)测试

Bus bus = new Bus();

bus.ShowPrice();

bus.PriceNationdayFloatup();

 

Train train = new Train();

train.ShowPrice();

train.PriceNationdayFloatup();

結果:

长途汽车石家庄到邢台50

国庆期间,汽车票在原价的基础上,上浮5%

火车石家庄到邢台40

国庆期间,火车票在原价的基础上,上浮3%

如果将来国家生产力高度发达,票价下调,那么,还要在两个类实现的基础上添加各自的通知方法。

现在以访问者来实现整个通知系统

(一)访问者抽象

涨价总是变,在不同的时期,总是要涨价。所以价格因素这里为访问者。

//上面的通知,涨价

    public abstract class NotifyVisitor

    {

        public abstract void Visit(Bus bus);

        public abstract void Visit(Train train);

    }

(二)客运部门

长途汽车,火车部门接受访问者的通知。

//交通工具

    public abstract class Vehicle

    {

        public abstract void ShowPrice();

 

        //过年涨价

        public abstract void Accept(NotifyVisitor visitor);

}

(三)   客运部门实现

//bus

    public class Bus : Vehicle

    {

        public override void ShowPrice()

        {

            Console.WriteLine("长途汽车石家庄到邢台50");

        }

        public override void Accept(NotifyVisitor visitor)

        {

            visitor.Visit(this);

        }

    }

 

    //train

    public class Train : Vehicle

    {

        public override void ShowPrice()

        {

            Console.WriteLine("火车石家庄到邢台40");

        }

 

        public override void Accept(NotifyVisitor visitor)

        {

            visitor.Visit(this);

        }

    }

(四)春运要涨价

这是一个实现的访问者

public class NewYearVisitor : NotifyVisitor

    {

        public override void Visit(Bus bus)

        {

            bus.ShowPrice();

            Console.WriteLine("春运开始了,汽车票在原价的基础上,上浮20%");

        }

 

        public override void Visit(Train train)

        {

            train.ShowPrice();

            Console.WriteLine("春运开始了,火车票在原价的基础上,上浮15%");

        }

}

它的目的就是通知两个部门,要涨价及涨价的细节。

(五)交通管理部门

用于确定要涨价的部门。这是可分配的:交通工具有很多种,长途汽车与火车是其中的两种,这次是两者都要涨!

public class TraffiMnagement

    {

        IList<Vehicle> _list = new List<Vehicle>();

 

        public void Add(Vehicle vehicle)

        {

            _list.Add(vehicle);

        }

 

        public void Detach(Vehicle vehicle)

        {

            _list.Remove(vehicle);

        }

 

        public void Accept(NotifyVisitor visitor)

        {

            foreach (Vehicle vv in _list)

            {

                vv.Accept(visitor);

            }

        }

    }

(六)测试

public void TestVisitor()

        {

            TraffiMnagement department = new TraffiMnagement();

 

            department.Add(new Bus());

            department.Add(new Train());

 

            department.Accept(new NewYearVisitor());

        }

 

结果:

长途汽车石家庄到邢台50

春运开始了,汽车票在原价的基础上,上浮20%

火车石家庄到邢台40

春运开始了,火车票在原价的基础上,上浮15%

(七)  国庆期间涨价

新加国庆访问者,其它的不用变动。

public class NationalDayNotifyVisitor : NotifyVisitor

    {

        public override void Visit(Bus bus)

        {

            bus.ShowPrice();

            Console.WriteLine("国庆节期间,汽车票在原价的基础上,上浮5%");

        }

 

        public override void Visit(Train train)

        {

            train.ShowPrice();

            Console.WriteLine("国庆节期间,火车票在原价的基础上,上浮3%");

        }

    }

(八)测试

public void TestVisitor()

        {

            TraffiMnagement department = new TraffiMnagement();

 

            department.Add(new Bus());

            department.Add(new Train());

            department.Accept(new NationalDayNotifyVisitor());

        }

 

结果:

长途汽车石家庄到邢台50

国庆节期间,汽车票在原价的基础上,上浮5%

火车石家庄到邢台40

国庆节期间,火车票在原价的基础上,上浮3%

(九)生产力发达了,票价要降了!

新加 愿望访问者。

public class WillVisitor : NotifyVisitor

    {

        public override void Visit(Bus bus)

        {

            bus.ShowPrice();

            Console.WriteLine("生产力发达了人民幸福了,汽车票在原价的基础上,下调90%");

        }

 

        public override void Visit(Train train)

        {

            train.ShowPrice();

            Console.WriteLine("生产力发达了人民幸福了,火车票在原价的基础上,下调90%");

        }

    }

(十)测试

public void TestVisitor()

        {

            TraffiMnagement department = new TraffiMnagement();

 

            department.Add(new Bus());

            department.Add(new Train());

 

            department.Accept(new WillVisitor());

        }

结果:

长途汽车石家庄到邢台50

生产力发达了人民幸福了,汽车票在原价的基础上,下调90%

火车石家庄到邢台40

生产力发达了人民幸福了,火车票在原价的基础上,下调90%


Visitor
模式通过所谓的双重分发(double dispatch)来实现在不更改Element类层次结构的前提下,在运行时透明的为类层次结构上的各个类动态添加新的操作。所谓双重分发即Visitor模式中间包括了两个多态分发:第一个为Accept方法的多态辨析;第二个为Visit方法的多态辨析(重载)
Visitor
模式最大缺点在于扩展类层次结构(添加新的Element子类),会导致Visitor类的改变,因此Visitor模式使用户Element类层子结构稳定,而其中的操作却经常面临频繁改动。

当我们需要增加一个交通工具的子类时,我们需要给NotifyVisitor类添加一个Visit函数,并且NotifyVisitor的每个派生类也必须添加。

博客园大道至简

http://www.cnblogs.com/jams742003/

转载请注明:博客园

目录
相关文章
|
7月前
|
弹性计算 资源调度 Serverless
ECS重启问题之跨账号重启调用如何解决
ECS(Elastic Compute Service,弹性计算服务)是云计算服务提供商提供的一种基础云服务,允许用户在云端获取和配置虚拟服务器。以下是ECS服务使用中的一些常见问题及其解答的合集:
|
弹性计算 关系型数据库 MySQL
通过会话管理端口转发功能访问ECS内部服务
本场景带您体验如何通过ali-instance-cli使用会话管理连接ECS实例,和通过ali-instance-cli对ECS内部服务进行端口转发。
|
关系型数据库 MySQL
|
存储 Cloud Native 分布式数据库
用户指南—实例管理—只读实例
本文将介绍如何为主实例添加只读实例。
115 0
用户指南—实例管理—只读实例
|
Cloud Native 分布式数据库 数据库
用户指南—实例管理—释放实例
本文介绍如何释放PolarDB-X实例。
377 0
用户指南—实例管理—释放实例
|
弹性计算 运维 负载均衡
如何实现多账号共享VPC
多账号共享VPC架构具备上下通吃的特点,今天就给大家介绍一下这个架构要如何落地实施。
958 0
如何实现多账号共享VPC
|
弹性计算
ECS查询特权接口DescribeAccountAttributes发布
弹性云服务ECS针对用户查询单个region各种quota限制、按量高配配置及一些特权信息。
1512 0

热门文章

最新文章