1、类层次结构的变化
类层次结构中可能常常因为引入新的操做,从而将类型变得脆弱...
2、动机(Motivation)
1)在软件构建过程当中,因为需求的改变,某些类层次结构中经常须要增长新的行为(方法),若是直接在基类中作这样的更改,将会给子类带来很繁重的变动负担,甚至破坏原有设计。
2)如何在不更改类层次结构的前提下,在运行时根据须要透明地为类层次结构上的各个类动态添加新的操做,从而避免上述问题?
3、意图(Intent)
表示一个做用于某对象结构中的各元素的操做。它能够在不改变各元素的类的前提下定义做用于这些元素的新的操做。
——《设计模式》GoF
4、实例:图形的绘制问题
1)需求的改变
//绘制图形
public abstract class Shape
{
public abstract void Draw();
/*问题:如今要在基类中添加一个方法:将图形总体移动
public abstract void MoveTo(Point p);
因为Shape中新增了MoveTo方法,其各个子类将不得不随之更改
添加了这个方法后,全部的子类都要去override这个方法
可是矩形的移动和其余图形的移动是不一样的,好比说移动圆只要移动圆心就能够了
而移动矩形能够须要移动对角线。还有一个可能就是子类不须要移动操做*/
}设计模式
//矩形
public class Rectangle : Shape
{
public override void Draw()
{
//...
}
}app
//圆形
public class Circle : Shape
{
public override void Draw()
{
//...
}
}ide
//直线
public class Line : Shape
{
public override void Draw()
{
//...
}
}this
2)程序的演变
public abstract class Shape
{
public abstract void Draw();
//预料到未来可能会引入新的操做
public abstract void Accept(ShapeVisitor v);
}spa
public abstract class ShapeVisitor
{
//重载了一系列方法,将Shape的子类做为参数,可是这个Visit也存在改变,这是一个弊端
//Visit的参数不是多态的,是具体类型
public abstract void Visit(Rectangle shape);//#1
public abstract void Visit(Circle shape); //#2
public abstract void Visit(Line shape); //#3
}设计
//矩形
public class Rectangle : Shape
{
public override void Draw()
{
//...
}
public override void Accept(ShapeVisitor v)
{
//v是一个多态的,this是一个指针
v.Visit(this); //调用#1方法
}
}指针
//圆形
public class Circle : Shape
{
public override void Draw()
{
//...
}
public override void Accept(ShapeVisitor v)
{
v.Visit(this); //调用#2方法
}
}对象
//直线
public class Line : Shape
{
public override void Draw()
{
//...
}
public override void Accept(ShapeVisitor v)
{
v.Visit(this); //调用#3方法 //第二次多态辨析
}
}it
public class MyVisitor :ShapeVisitor
{
public override void Visit(Rectangle shape)//#1
{
//增长对Rectangle的操做
}
public override void Visit(Circle shape) //#2
{
//增长对Circle的操做
}
public override void Visit(Line shape) //#3
{
//增长对Line的操做
}
/*为何Visit的参数是具体类型,而不用抽像类型:用具体类型重载方
**法是让编绎器辨析,而用抽像类型则须要咱们本身辨析。
public override void Visit(Shape shape)
{
if (shape is Rectangle)
{
//增长对Rectangle的操做
}
else if (shape is Circle)
{
//增长对Circle的操做
}
else if (shape is Line)
{
//增长对Line的操做
}
}
**这里面换汤不换药,仍是不能解决Shape抽象类添加子类的问题,它必须稳定
**/
}io
//应用
public class App
{
ShapeVisitor visitor;
public App(ShapeVisitor visitor)
{
this.visitor = visitor;
}
public void Process(Shape shape)
{
//两处多态:
// 1.Accept方法的调用对象:shape
// 2.Accept方法的参数:visitor
shape.Accept(visitor);//第一次多态辨析
}
}
/*动态的添加方法
**App app = new App(new MyVisitor());
**app.Process(new Line);
*/
5、Visitor模式的几个要点 1)Visitor模式经过所谓双重分发(double dispatch)来实如今不更改Element类层次结构的前提下,在运行时透明地为类层次结构上的各个类动态添加新的操做。 2)所谓双重分发即Visitor模式中间包括了两个多态分发(注意其中的多态机制):第一个为accept方法的多态辨析;第二个为visit方法的多态辨析。 3)Visitor模式的最大缺点在于扩展类层次结构(增添新的Element子类),会致使Visitor类的改变。所以Visitor模式适用于“Element类层次结构稳定,而其中的操做却常常而临频繁改动”。 分析:任何一个设计模式都不可能彻底解决问题,即便是几个设计模式组合也不可能,由于每个设计模式都是假定了一个变化和一个稳定,若是假定的稳定不成立,那么设计模式将是一个误用,由于它不能解决问题。