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

简介: 场景:长途汽车票、火车票价格调整   描述:春运开始了,人流高峰期,打工的人群要回家过年了,票价要涨了!   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/

转载请注明:博客园

目录
相关文章
|
23天前
|
安全
代理ip的优势、用途及注意事项
代理ip的优势、用途及注意事项
|
2月前
|
存储 Java
|
11月前
|
设计模式 缓存 安全
Java代理模式:如何优雅地控制对象访问?
Java代理模式:如何优雅地控制对象访问?
163 1
|
弹性计算 Ubuntu Linux
服务器实例
使用Ubuntu OS和Apache完成对ECS公网IP的监听和浏览器访问
170 0
服务器实例
|
数据库
模式方法模式实例数据库访问
模式方法模式实例数据库访问
56 0
模式方法模式实例数据库访问
|
安全 编译器 API
C++在资源管理类中提供对原始资源的访问
C++在资源管理类中提供对原始资源的访问
128 0
|
运维
实例维护属性-让您的实例更可控
阿里云给实例加入了维护属性这个属性,通过对该属性的修改,您可以自主选择实例出现非预期宕机或者主动运维事件之后的状态,为您的操作提供更高的透明度和便捷度
2347 0
实例维护属性-让您的实例更可控
【产品功能】创建实例支持同时加入多个安全组
背景: 长期以来,创建ECS实例只支持同时加入一个安全组,但是某些友商支持多个安全组,这会增加混合云用户上云成本,比如基于Terraform的国际站用户想迁移到阿里云就要修改大量代码。为此ECS提供了创建实例同时加入多个安全组的功能,此功能一方面可以让上述用户最小成本使用阿里云,另外一方面也降低实例加入多个安全组的复杂度,可以方便的随实例创建同时加入多个安全组。
1135 0
|
弹性计算 运维 监控
阿里云新发布ECS状态变化类事件
阿里云ECS在已有的系统事件的基础上,通过云监控新发布了状态变化类事件和抢占型实例的中断通知事件。利用这些新发布的事件,客户可以将ECS的完整生命周期实时的同步到自己的日志里或者数据库里,满足查询和审计的需要,或者直接触发函数计算进行一些自动化的运维操作。
6168 0