类层次结构的变化
类层次结构中可能经常由于引入新的操作,从而将类型变得脆弱...
1、动机
在软件构建过程中,由于需求的改变,某些类层次结构中常常需要增加新的行为(方法),如果直接在基类中做这样的更改,将会给子类带来很繁重的变更负担,甚至破坏原有设计。
如何在不更改类层次结构的前提下,在运行时根据需要透明地为类层次结构上的各个类动态添加新的操作,从而避免上述问题?
2、意图
表示一个作用于某对象结构中的各元素的操作。它可以在不改变各元素的类的前提下定义作用于这些元素的新的操作。
3、图
4、代码
public abstract class Shape
{
public abstract void Draw();
//问题:由于Shape中新增了MoveTo方法,其各个子类将不得不随之更改
public abstract void MoveTo(Point p );
}
public class Rectangle : Shape
{
public override void Draw()
{
}
}
public class Circle : Shape
{
public override void Draw()
{
}
}
public class Line : Shape
{
public override void Draw()
{
}
}
------------------------------------------------------------
public abstract class Shape
{
public abstract void Draw();
//预料到将来可能会引入新的操作
public abstract void Accept( ShapeVisitor v );
}
public abstract class ShapeVisitor
{
public abstract void Visit( Recangle 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.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( Recangle shape )
{
//增加对Recangle的操作
}
public override void Visit( Circle shape )
{
//增加对Circle的操作
}
public override void Visit( Line shape )
{
//增加对Line的操作
}
}
class App
{
ShapeVisitor visitor;
public App(ShapeVisitor visitor)
{
this.visitor = visitor;
}
public static void Process( Shape shape )
{
shape.Accept( visitor );//第一层辨析
}
}
App app = new App( new MyVisitor() );
app.Process( new Line());
--------------------------------------------------------------------------------------
public interface Visitor
{
void visit(NodeA node);
void visit(NodeB node);
}
public class VisitorA : Visitor
{
void visit(NodeA node)
{
nodeA.operationA();
}
void visit(NodeB node)
{
nodeB.operationB();
}
}
public class VisitorB : Visitor
{
void visit(NodeA node)
{
nodeA.operationA();
}
void visit(NodeB node)
{
nodeB.operationB();
}
}
abstract public class Node
{
public abstract void accept(Vistor visitor);
}
public class NodeA : Node
{
public void accept( Visitor visitor )
{
visitor.visit( this );
}
public void operationA()
{
}
}
public class NodeB : Node
{
public void accept( Visitor visitor )
{
visitor.visit( this );
}
public void operationB()
{
}
}
public class ObjectStructure
{
private ArrayList nodes = new ArrayList();
public void action( Visitor visitor )
{
foreach( object node in nodes )
{
( (Node)node ).accept( visitor );
}
}
public void Add( Node node )
{
nodes.Add( node );
}
}
public Class Client
{
private static ObjectStructure aObjects;
private static Visitor visitor;
public static void main( String[] args )
{
aObjects = new ObjectStructure();
aObjects.Add( new NodeA() );
aObjects.Add( new NodeB() );
visitor = new VisitorA();
aObjects.action( visitor );
}
}
5、要点
(1) Visitor模式通过所谓双重分发(double dispatch)来实现不更改Element类层次结构的前提下,在运行时透明地为类层次结构上的各个类动态添加新的操作。
(2) 所谓双重分发即Visitor模式中间包括了两个多态分发(注重其中的多态机制):第一个为accept方法的多态辨析,第二个为visit方法的多态辨析。
(3) Visitor模式的最大缺点在于扩展类层次结构(增添新的Element子类),会导致visitor类的改变。因此Visitor模式适用于"Element"类层次结构稳定,而其中的操作经常面临频繁改动。