我的一个visitor实作


public interface Visitable
{
void accept(Visitor visitor);
}

public interface Visitor
{
void visit(Visitable visitable);
}


public class VisitableA implements Visitable
{
public String Call(){
return "AAA";
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
}

public class VisitorA implements Visitor
{ public void visit(Visitable visitable) {
if (visitable instanceof VisitableA)
{
System.out.println(((VisitableA)visitable).Call());
}
}

}


public class Client{
public static void main(String args[])
{
Visitor visitor=new VisitorA();
Visitable visitable=new VisitableA();
visitable.accept(visitor);
}
}

不错,关键是要结合自己的项目能应用,因为这时你就有两件事要协调和处理,一边是visitor模式各个角色,一边是实际项目的各个角色,如何对号入坐是比较费劲的。

delphi版本的:
unit UVisitor;
interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, forms,
Dialogs, StdCtrls;

type

Tform1 = class(Tform)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
form1: Tform1;

implementation

type
TVisitor=class;
TVisitable=class
procedure accept(visitor:TVisitor);virtual;abstract;
end;
TVisitor=class
procedure visit(visitable:TVisitable);virtual;abstract;
end;
TVisitableA=class(TVisitable)
public
procedure accept(visitor:TVisitor);override;
function Call():string;
end;
TVisitorA=class(TVisitor)
public
procedure visit(visitable:TVisitable);override;
end;


{$R *.dfm}

{ TVisitableA }

procedure TVisitableA.accept(visitor: TVisitor);
begin
inherited;
visitor.visit(self);
end;

function TVisitableA.Call: string;
begin
Result:='AAA';
end;

{ TVisitorA }

procedure TVisitorA.visit(visitable: TVisitable);
begin
inherited;
if visitable is TVisitableA then
showmessage(TVisitableA(visitable).Call);
end;

procedure Tform1.Button1Click(Sender: TObject);
var
v:TVisitor;
vb:TVisitable;
begin
v:=TVisitorA.Create;
vb:=TVisitableA.Create;
vb.accept(v);
v.Free;
vb.Free;
end;

end.

c版本的:
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.forms;
using System.Data;
namespace WindowsApplication2
{
///
/// form1 的摘要说明。
///
public interface IVisitable
{
void accept(IVisitor visitor);
}


public interface IVisitor
{
void visit(IVisitable visitable);
}

public class VisitorA:IVisitor
{
public void visit(IVisitable visitable){
if (visitable is VisitableA){
MessageBox.Show(((VisitableA)visitable).Call(),"");
}
}
}

public class VisitableA:IVisitable
{
public String Call()
{
return "AAA";
}
public void accept(IVisitor visitor){
visitor.visit(this);
}
}

///
public class form1 : System.Windows.forms.form
{
private System.Windows.forms.Button button1;
///
/// 必需的设计器变量。
///
private System.ComponentModel.Container components = null;

public form1()
{
//
// Windows 窗体设计器支持所必需的
//
InitializeComponent();

//
// TODO: 在 InitializeComponent 调用后添加任何构造函数代码
//
}

///
/// 清理所有正在使用的资源。
///
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

region Windows form Designer generated code
///
/// 设计器支持所需的方法 - 不要使用代码编辑器修改
/// 此方法的内容。
///
private void InitializeComponent()
{
this.button1 = new System.Windows.forms.Button();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(80, 72);
this.button1.Name = "button1";
this.button1.TabIndex = 0;
this.button1.Text = "button1";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
this.ClientSize = new System.Drawing.Size(292, 272);
this.Controls.AddRange(new System.Windows.forms.Control[] {
this.button1});
this.Name = "form1";
this.Text = "form1";
this.ResumeLayout(false);

}
endregion

///
/// 应用程序的主入口点。
///
[STAThread]
static void Main()
{
Application.Run(new form1());
}

private void button1_Click(object sender, System.EventArgs e)
{
IVisitor v=new VisitorA();
IVisitable vb=new VisitableA();
vb.accept(v);
}
}
}

vb.net版本的:
Public Class form1
Inherits System.Windows.forms.form
Public MustInherit Class Visitor
Public MustOverride Sub visit(ByRef vb As Visitable)
End Class

Public MustInherit Class Visitable
Public MustOverride Sub accept(ByRef v As Visitor)
End Class

Public Class VisitorA
Inherits Visitor
Public Overrides Sub visit(ByRef vb As Visitable)
If vb.GetType Is GetType(VisitableA) Then
MessageBox.Show(CType(vb, VisitableA).CallOp, "")
End If
End Sub
End Class

Public Class VisitableA
Inherits Visitable
Public Function CallOp() As String
Return "AAA"
End Function
Public Overrides Sub accept(ByRef v As Visitor)
v.visit(Me)
End Sub
End Class


Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim vb As Visitable
Dim v As Visitor
vb = New VisitableA()
v = New VisitorA()
vb.accept(v)
vb = Nothing
v = Nothing
End Sub
End Class

晕。。。佩服

使用
if (visitable instanceof VisitableA)
的方式,已经是在使用 RTTI 了。而 GoF 的 Visitor 实现并没有使用 RTTI。按你的例子,改写如下:


public interface Visitable
{
void accept(Visitor visitor);
}

public class VisitableA implements Visitable
{
public String CallA()
{
return "AAA";
}

public void accept(Visitor visitor)
{
visitor.VisitVisitableA(this);
}
}

public class VisitableB implements Visitable
{
public String CallB()
{
return "BBB";
}

public void accept(Visitor visitor)
{
visitor.VisitVisitableB(this);
}
}

public class Visitor
{
public void VisitVisitableA(VisitableA va)
{
String s = va.CallA();
System.out.println(s);
}
public void VisitVisitableB(VisitableB vb)
{
String s = vb.CallB();
System.out.println(s);
}
}

GoF的原文
Visitor: 表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。

是不是这样的实现才能符合这段话?关键是“不改变各元素的类”。


public class A
{
public String CallA()
{
return "AAA";
}
}

public class B
{
public String CallB()
{
return "BBB";
}
}

public interface Visitable
{
void accept(Visitor visitor);
}

public class VisitableA extends A implements Visitable
{
public void accept(Visitor visitor)
{
visitor.VisitA(this);
}
}

public class VisitableB extends B implements Visitable
{
public void accept(Visitor visitor)
{
visitor.VisitB(this);
}
}

public class Visitor
{
public void VisitA(A a)
{
String s = a.CallA();
System.out.println(s);
}
public void VisitB(B b)
{
String s = b.CallB();
System.out.println(s);
}
}

gof的visitor接口可以改成函数重载的型式,
我的是用了一个catch-all的visitor接口,
看banq能不能改成非RTTI的型式?:)

使用重载方法的好处是,可以统一用visit方法,
通过传不同参数来完成访问。但哪个程序员偷偷
把以前的类继承结构修改了,添加了一个新类,
那么在访问这个类时,就会出现一个编译错误,
解决办法就是用一个catch-all的visit方法,
给每个继承这个方法的visitor一个缺省的实现,
为了处理新类,写一个新的visitor,用RTTI来
判断(type switch),但如果新类太多就会出现
很长的type switch,也就是visitor模式的缺点,
解决的办法就是大家都不要过于依赖继承,
要prefer compositon to inheritance:)

呵呵,不明白你说的

“catch-all的visitor接口”,呵呵

也写点对搂主写的code的理解

一个参观者,一个招待的人
招待的人可以接受参观者并且根据参观者的不同提供各项服务
所以招待者class里面应该定义对于参观者的接受功能,定义
提供的各项服务,

参观者class里面定义可以根据自己的身份去使用(调用)招待者提供的服务的方法

于是
来了一个参观者,来了一个接待者

接待者接待了参观者,并且告诉他所能提供的服务
于是参观者根据自己的身份去选择了某一个服务
。。。。。。故事就这么开始了

manbaum 的方法实际上变成了一群招待者和一个参观者的问题
这群招待者中的每一个提供一类服务
而参观者根据自己的身份可以去选择某一个招待者去为自己提供服务

那个好?

catch-all的visitor可以捕获
所有可能的新增的visitable类,
而无需重新修改所有的visitor类
继承结构,缺点是如果新增的类
很多的话会使用很长的type switch。

hehe ,反对你的说法