2009-08-09 46 views
2

我似乎没有在访问者模式的使用场景中找到它(或者我可能没有得到它)​​。它也不是分层的。针对条件的访问者模式?

让我们使用身份验证的例子。 UserAuthenticator认证用户给出的凭证。它返回一个结果对象。结果对象包含身份验证结果:身份验证成功,未成功,因为未找到用户名,未成功,因为使用了非法字符等。客户端代码可能会使用条件来处理此问题。 In pseudocode:

AuthResult = Userauthenticator.authenticate(Username, Password) 
if AuthResult.isAuthenticated: do something 
else if AuthResult.AuthFailedBecauseUsernameNotFound: do something else 
else if etc... 

访客模式会适合在这里吗? :

Authresult.acceptVisitor(AuthVisitor) 

Authresult然后调用AuthVisitor的方法根据结果:

AuthVisitor.handleNotAuthenticatedBecauseUsernameNotFound 

回答

1

我不会建议使用模式,因为还没有为取得意图。

the visitor patterns的意图是:

  • 表示待上的对象结构的元件所执行的操作。访问者可以让你定义一个新的操作而不需要改变它所操作的元素的类。
  • 经典技术来恢复丢失的类型信息。
  • 做基于两个对象的类型是正确的。
  • 双重分派

如果你计划做各种认证方法,该解决方案将是有益的,但如果你打算只做一个,你无论如何都要使用条件。

+0

我不同意不使用他们没有制造的东西。有些东西可能会解决问题而不打算这样做。如果访问者模式能够很好地解决我的问题,为什么我不应该使用它?那么问题就变成:解决方案是否是一个好的解决方案。没有人以这种方式使用这并不意味着它是一个不好的解决方案,尽管它可能暗示了这个方向。更重要的是为什么这是一个好的或坏的解决方案。 如果McGyver接受了你的建议,他将会失业。 – koen 2009-08-09 11:56:29

+0

另一件事是:认证处理的方式是不可知的例子。我不明白为什么我的示例将UserAuthenticator限制为只有一种身份验证方式(例如,只有LDAPUserAuthentication,OpenIdUserAuthentication等) – koen 2009-08-09 11:58:22

1

游客是当你数据不为自己的行为快速更改宝贵的设计。一个典型的例子是一个解析树:

  • 你的类层次结构(数据)被冻结
  • 您的行为而改变太多,你不想打破你的类增加一个虚方法

我不认为一个游客在这里是有价值的解决方案,因为每次你添加AuthResult的子类,你打破你的访问者。

游客大约是交易封装双调度

您可以尝试类似的做法:

interface Handler { 

    void onUsernameNotFound(); 

    void onWrongPassword(); 

    void authOk(); 
} 

interface Authenticator { 
    void authenticate(String username, String password, Handler handler); 
} 

class SimpleAuthenticator implements Authetnciator { 

    void authenticate(String username, String password, Handler handler) { 
     if (username.equals("dfa")) { 
      if (password.equals("I'm1337")) { 
       handler.authOk(); 
      } else { 
       handler.onWrongPassword(); 
      } 
     } else { 
      handler.onUsernameNotFound(); 
     } 
    } 
} 

一些处理程序策略及DCS:

class FatalHandler implements Handler { 

    void onUsernameNotFound() { 
     throw new AuthError("auth failed"); 
    } 

    void onWrongPassword() { 
     throw new AuthError("auth failed"); 
    } 

    void authOk() { 
     /* do something */ 
    } 
} 

和:

class DebugHandler implements Handler { 

    void onUsernameNotFound() { 
     System.out.println("wrong username"); 
    } 

    void onWrongPassword() { 
     System.out.println("wrong password"); 
    } 

    void authOk() { 
     System.out.println("ok"); 
    } 
} 

现在你可以封装在Handler■错误处理和operatorion这比Visitor少得多的代码,因为你并不需要双重dispa这里。

+0

我会使用此设计。然而,有一种观察:您评论说访问者不适合,因为AuthResult的每个新子类都需要对访问者进行更改。这里Handler上的方法对应于不同的结果,有效地是AuthResult的不同子类。同样的耦合属于...新的可能结果Handler接口和所有实现都有很大变化。鉴于我们有两个维度的变化,Auth + Handler,我们实际上距离Double Dispatch需求有多远? – djna 2009-08-09 12:00:17

+0

我必须错过一些东西。为什么Auth子类会对访问者失败?可能有一个实现acceptVisitor的抽象基类。 我看到一个策略如何在这里工作,但在某种程度上,一个策略与访客恕我直言相关,除了它不做层次结构。 – koen 2009-08-09 12:04:29

+0

@djna:由于您需要一个if-elseif链来构建正确的具体AuthResponse类,因此您需要重复访问逻辑......然后您需要另一个if-elseif链来进行调度 – dfa 2009-08-09 13:12:38