4

我只是读这篇文章:业务逻辑(以及那是什么?)应该在哪里生存,以及如何用Spring来实现?

http://www.tutorialized.com/view/tutorial/Spring-MVC-Application-Architecture/11986

我觉得这很棒。它很好地解释了层架构,我很高兴我正在使用的架构非常符合他的描述。

但有一两件事,我似乎并没有得到:

第一:究竟什么是业务逻辑又是什么呢不是?在他所说的文章中(并且他不是唯一一个),业务逻辑应该放在领域模型中。因此Account类应具有知道如何激活Accountactivate()方法。根据我的理解,这可能涉及一些持久性工作。但是领域模型不应该有DAO的依赖。只有服务层应该知道DAO。

那么,业务逻辑就是一个域实体可以对自己做什么?与activate()类似,方法会将active属性设置为true,并将dateActivated属性设置为new Date(),然后服务的任务是首先拨打account.activate()和第二个dao.saveAccount(account)?什么需要外部依赖去服务?这就是我到现在为止所做的。

public AccountServiceImpl implements AccountService 
{ 
    private AccountDAO dao; 
    private MailSender mailSender; 

    public void activateAccount(Account account) 
    { 
    account.setActive(true); 
    account.setDateActivated(new Date()); 
    dao.saveAccount(account); 
    sendActivationEmail(account); 
    } 
    private void sendActivationEmail(Account account) 
    { 
    ... 
    } 
} 

这与他所说的相反,我认为,不是吗?

我也没有得到的是关于如何使用像Account这样的Spring线域对象的例子。如果Account自己发送电子邮件,则需要这样做。

鉴于此代码:

import org.springframework.mail.MailSender; 
import org.springframework.mail.SimpleMailMessage; 

public class Account { 
    private String email; 
    private MailSender mailSender; 
    private boolean active = false; 

    public String getEmail() { 
     return email; 
    } 

    public void setEmail(String email) { 
     this.email = email; 
    } 

    public void setMailSender(MailSender mailSender) { 
     this.mailSender = mailSender; 
    } 

    public void activate() { 
     if (active) { 
     throw new IllegalStateException("Already active"); 
     } 

     active = true; 
     sendActivationEmail(); 
    } 

    private void sendActivationEmail() { 
     SimpleMailMessage msg = new SimpleMailMessage(); 
     msg.setTo(email); 
     msg.setSubject("Congrats!"); 
     msg.setText("You're the best."); 
     mailSender.send(msg); 
    } 
} 

如果我使用Hibernate,我可以以电汇mailSender使用DependencyInjectionInterceptorFactoryBean。如果我使用JDBC来代替,那么我真的会写下以下繁琐的代码?另外,当我在MVC控制器中为Account创建新实例时,让我们假设将它填充到模型中?

BeanFactory beanFactory = new XmlBeanFactory( 
    new ClassPathResource("chapter3.xml")); 
    Account account = new Account(); 
    account.setEmail("[email protected]"); 
    ((AutowireCapableBeanFactory)beanFactory).applyBeanPropertyValues( 
     account, "accountPrototype"); 
    account.activate(); 

这不可靠,很麻烦,不是吗?每当我看到一个Account的实例时,我都不得不问自己该创建对象的位置。此外,如果我采用这种方法:我没有可以传递的一个appContext.xml,但有几个,一个用于持久性,一个用于服务配置。我会怎么做?另外,每创建一个这样的实例或者我错过了什么,这会创建一个全新的上下文?

有没有更好的解决方案呢?

任何帮助,非常感谢。

回答

5

我觉得发送激活邮件动作不是业务层的一部分,在这里,在这里你的域逻辑是账号激活行动,那块逻辑应该活在DomainObject与名称Accountactivate()方法)。 发送激活邮件动作是infrastructureapplication层的一部分。

服务是处理帐户激活请求并连接业务层和其他对象的对象。服务需要给定的帐户,激活它们并执行发送激活电子邮件的行为MailSenderService或类似的东西。

短采样:

public AccountServiceImpl implements AccountService 
{ 
private AccountDAO dao; 
private MailSenderService mailSender; 

public void activateAccount(AccountID accountID) 
{ 
    Account account = dao.findAccount(accountID); 
    .... 
    account.activate(); 
    dao.updateAccount(account); 
    .... 

    mailSender.sendActivationEmail(account); 
} 

} 

下一步,我可以建议是业务层 的完全分离和基础设施层。这可以通过引入 业务事件来获得。服务不再需要执行发送 电子邮件的操作,它会创建事件来通知其他层关于帐户激活的 。

在春天,我们有两个工具来处理事件ApplicationEventPublisherApplicationListener

短例如,服务,发布域事件:

public AccountActivationEvent extends ApplicationEvent { 
    private Account account; 

    AccountActivationEvent(Account account) { 
     this.account = account; 
    } 

    public Account getActivatedAccount() { 
     return account; 
    } 
} 

public AccountServiceImpl implements AccountService, ApplicationEventPublisherAware 
{ 
private AccountDAO dao; 
private ApplicationEventPublisher epublisher; 

public void setApplicationEventPublisher(ApplicationEventPublisher epublisher) { 
    this.epublisher = epublisher; 
} 

public void activateAccount(AccountID accountID) 
{ 
    Account account = dao.findAccount(accountID); 
    .... 
    account.activate(); 
    dao.updateAccount(account); 
    .... 

    epublisher.publishEvent(new AccountActivationEvent(account)); 
} 

} 

和域事件侦听器,在基础设施层:

public class SendAccountActivationEmailEventListener 
     implements ApplicationListener<AccountActivationEvent> { 

    private MailSenderService mailSender; 

    .... 

    public final void onApplicationEvent(final AccountActivationEvent event) { 
    Account account = event.getActivatedAccount(): 
    .... perform mail ... 
    mailSender.sendEmail(email); 
    } 
} 

现在,您可以添加其他激活类型,日志等基础的东西支持而不改变,并污染你的域名(业务)层。

啊,你可以在the documentation了解更多关于春季活动的信息。

+0

扼杀,谢谢你的回答。所以,基本上我的建议是真实的,即业务逻辑是“业务实体可以独立完成而不使用其他层的东西”。其余的是服务任务(或基础设施或任何你称之为的)。对我来说有点意义,不过直觉上,我会打电话来决定是发送一封确认电子邮件还是不是“商业决策”,我想这就是让我困惑的原因。 – marc82ch 2012-07-30 11:20:16

+1

是否发送确认电子邮件的决定 - 是的是“业务决策”,但发送不是业务任务。 :)我不确定这个决定是否是Account的职责范围。这很可能是AccountService的一项任务。 – masted 2012-07-30 12:54:08

相关问题