我的一个visitor实作

03-04-05 VRGL

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);

}

}

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

VRGL
2003-04-06 17:43
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.

VRGL
2003-04-06 17:43
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);

}

}

}

VRGL
2003-04-06 17:44
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

banq
2003-04-06 21:51
晕。。。佩服

manbaum
2003-04-07 11:55
使用

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);
    }
}
<p>

manbaum
2003-04-07 12:12
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);
    }
}
<p>

VRGL
2003-04-07 18:16
gof的visitor接口可以改成函数重载的型式,

我的是用了一个catch-all的visitor接口,

看banq能不能改成非RTTI的型式?:)

VRGL
2003-04-07 21:05
使用重载方法的好处是,可以统一用visit方法,

通过传不同参数来完成访问。但哪个程序员偷偷

把以前的类继承结构修改了,添加了一个新类,

那么在访问这个类时,就会出现一个编译错误,

解决办法就是用一个catch-all的visit方法,

给每个继承这个方法的visitor一个缺省的实现,

为了处理新类,写一个新的visitor,用RTTI来

判断(type switch),但如果新类太多就会出现

很长的type switch,也就是visitor模式的缺点,

解决的办法就是大家都不要过于依赖继承,

要prefer compositon to inheritance:)

richardluopeng
2003-04-08 09:20
呵呵,不明白你说的

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

张二狠
2003-04-10 15:19
也写点对搂主写的code的理解

一个参观者,一个招待的人

招待的人可以接受参观者并且根据参观者的不同提供各项服务

所以招待者class里面应该定义对于参观者的接受功能,定义

提供的各项服务,

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

于是

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

接待者接待了参观者,并且告诉他所能提供的服务

于是参观者根据自己的身份去选择了某一个服务

。。。。。。故事就这么开始了

张二狠
2003-04-10 15:31
manbaum 的方法实际上变成了一群招待者和一个参观者的问题

这群招待者中的每一个提供一类服务

而参观者根据自己的身份可以去选择某一个招待者去为自己提供服务

那个好?

VRGL
2003-04-10 17:44
catch-all的visitor可以捕获

所有可能的新增的visitable类,

而无需重新修改所有的visitor类

继承结构,缺点是如果新增的类

很多的话会使用很长的type switch。

richardluopeng
2003-04-11 13:32
hehe ,反对你的说法

猜你喜欢