2010-09-03 66 views
0

我有一个Email对象有两个属性,标签和值。系统用户需要验证他们的电子邮件,然后才能在系统中使用它。验证过程非常简单:域对象属性和封装

  1. 设置了电子邮件
  2. 激活码发送一封电子邮件,激活码验证电子邮件是有效的

电子邮件对象如下所示:

class Email { 
    String label 
    String value 
    EmailStatus status 
    String activationCode 

    boolean requestVerification() { 
     // Set the activationCode that will be refereced to change the email status 
     this.activationCode = UUID 
     // Raise an event to send a notification email by a communication service 
     EventManager.fire('emailVerificationRequest',this) 
    } 

一切工作正常,除了activationCode属性不电子邮件对象中正确感觉。它并没有描述对象的状态,它仅用于电子邮件验证过程。所以我修改了我的代码来引入一个名为ActivationToken的新对象。该对象将用于封装activationCode。这里的电子邮件对象

class Email { 
    String label 
    String value 
    EmailStatus status 

    boolean requestVerification() { 
     new ActivationToken(target:this,code:UUID,expiryDate:new Date()).save() 
     // Raise an event to send a notification email by a communication service 
     EventManager.fire('emailVerificationRequest',this) 
    } 

class ActivationToken { 
    Email target 
    String code 
    Date expiryDate 
} 
  1. 的新版本是这样一个声音域设计还是我复杂的我对象没有
  2. 是否requestVerification方法属于Email对象首先还是应放置在其他地方;在服务中,或在一个过程中。
  3. 有没有办法,我可以按照解决类似的问题

更新

我想解释一下,为什么我连第二重构后保留电子邮件域对象的requestVerfication方法部分的任何设计模式做法。

我有一个直接与域对象通过调度员以下列方式进行交互的远程接口:

remote://email/6/do/requestVerification 

本来我想继续通过域对象渠道后端所有的通信和是否有需要与我使用IOC将其注入域对象并使用域对象作为代理的服务进行交互。远程接口和域对象之间的分离看起来很干净,但是结果却是一个非常糟糕的想法,因为它扼杀了域设计,并将无用的依赖性引入了与外部对象无关(在这种情况下为EmailVerificationService),这与该行为无关或域的状态方面对象

另一种解决方案来解决这个可能是保持在其中其自然地所属的业务的requestVerification方法和引入新的语法的通信协议如:

remote://service/email/do/requestVerification 

你们有什么感想 ?

谢谢

-Ken

回答

0

你已完成了从分离电子邮件 ActivationToken正确的步骤 - 从概念上它们是独立的事情(顺便说一句,我会用EmailActivationToken为明晰)。

通常,将使用EmailVerificationService来封装验证逻辑。

+0

请参阅我的问题的更新,解释为什么我没有选择服务方法的原因。您的意见非常感谢。谢谢 – ken 2010-09-03 14:34:09

1

就我个人而言,我发现两种方法都可以接受,但更喜欢第二种。我将用什么来确定哪种方法,将成为领域专家的输入。在对域进行建模时,激活码是否是明确要求的一部分,或者您是否有理由在电子邮件帐户进行验证后进行维护?如果你没有明确的理由去采用你的第一种方法,我会坚持你的第二种方法。

在问候你的个人问题:

  1. 我不会尽可能考虑它被复杂化更从域抽象的服务水平的关注你的对象中去。是的,这是更多的代码和更多的工作,但可能是更好的方法 - 除非你有明确的理由使用原始方法。

  2. 如上所述,我真的认为这是服务级别的责任,应该是某种EmailVerificationService。在域模型本身,只有真的在意,如果电子邮件是有效的,而不是它被验证的手段。

  3. 在我看来,您已经在使用最好的方法。从域对象中引发事件的事件总线是干净可靠的。

+0

请参阅我的问题的更新,解释为什么我没有选择服务方法的原因。您的意见非常感谢。谢谢 – ken 2010-09-03 14:34:32

0

我认为在ActivationToken中封装功能是一个好主意。但通过在Email类中初始化ActivationToken,您已创建对外部资源的隐藏依赖项。这有效地使Email很难进行单元测试,并被其他具有另一激活方案的客户端重新使用。

相反,您可能需要使用Dependency Injection/Inversion of Control模式将ActivationToken注入Email类。这使您可以注入不同的激活策略,并打开易于对Email类进行单元测试。

要做到这一点你需要ActivationToken和接口Email类的构造函数应该参照的对象实现了这个接口:

interface IActivationToken 
{ 
    void Save(object target, string code, DateTime date); 
} 

class Email 
{ 
    IActivationToken token; 
    // Other properties go here. 

    public Email(IActivationToken token) 
    { 
     this.token = token; 
    } 

    boolean RequestVerification() 
    {  
     token.Save(this, code, date);   
     // Raise an event to send a notification email by a communication service  
     EventManager.fire('emailVerificationRequest', this)  
    }  
} 

现在Email类对外部资源没有隐藏的依赖。

+0

请参阅我的问题的更新,解释为什么我没有选择服务方法的原因。您的意见非常感谢。谢谢 – ken 2010-09-03 14:35:04