行为型模式:Visitor 访问者模式

                                                             行为型模式:Visitor 访问者模式

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()
  {
    //...
  }
}

//圆形
public class Circle : Shape
{
  public override void Draw()
  {
    //...
  }
}

//直线
public class Line : Shape
{
  public override void Draw()
  {
    //...
  }
}

  2)程序的演变
public abstract class Shape
{
  public abstract void Draw();
  //预料到将来可能会引入新的操作
  public abstract void Accept(ShapeVisitor v);
}

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方法 //第二次多态辨析
  }
}

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抽象类添加子类的问题,它必须稳定
  **/
}

//应用
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类层次结构稳定,而其中的操作却经常而临频繁改动”。
      分析:任何一个设计模式都不可能完全解决问题,即使是几个设计模式组合也不可能,因为每一个设计模式都是假定了一个变化和一个稳定,如果假定的稳定不成立,那么设计模式将是一个误用,因为它不能解决问题。

你可能感兴趣的:(行为型模式:Visitor 访问者模式)