8

私はちょうどこの記事を読んでいました:

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

私はそれが素晴らしいと思います。それはレイヤーアーキテクチャをうまく説明していて、私が取り組んでいるアーキテクチャが彼が説明しているものであることがうれしかったです。

しかし、私が得ていないように思われることが1つあります。

まず、ビジネスロジックとは正確には何であり、そうではないのでしょうか。彼が言う記事の中で(そして彼だけではありません)、そのビジネスロジックはドメインモデルに組み込まれるべきです。したがって、Accountクラスには、activate()をアクティブ化する方法を知っているメソッドが必要Accountです。私の理解では、これにはおそらく永続的な作業が含まれます。ただし、ドメインモデルにDAOの依存関係があってはなりません。サービス層のみがDAOについて知っている必要があります。

では、ビジネスロジックは、ドメインエンティティがそれ自体で実行できることだけでしょうか。activate()メソッドがプロパティをに設定し、さらにactiveプロパティをに設定するように、サービスのタスクは最初に呼び出し、次に?そして、外部の依存関係がサービスに必要なのは何ですか?それは私が今までほとんどやっていたことです。truedateActivatednew 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)
  {
    ...
  }
}

これは彼の言うこととは対照的だと思いますね

私も得られないのは、のような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を使用する場合、DependencyInjectionInterceptorFactoryBean配線するためにを使用できますmailSender。代わりにJDBCを使用する場合、次の面倒なコードを実際に記述しますか?さらに、MVCコントローラーでアカウントの新しいインスタンスを作成するときも、モデルにデータを入力するとしますか?

  BeanFactory beanFactory = new XmlBeanFactory(  
     new ClassPathResource("chapter3.xml"));  
  Account account = new Account();  
  account.setEmail("email@example.com");  
  ((AutowireCapableBeanFactory)beanFactory).applyBeanPropertyValues(  
        account, "accountPrototype");  
  account.activate(); 

これは信頼できず、非常に面倒ですよね?Accountのインスタンスを見るたびに、そのオブジェクトがどこで作成されたかを自問する必要があります。さらに、このアプローチを採用する場合、渡すことができるappContext.xmlは1つではありませんが、永続性用に1つ、サービス構成用に1つ、いくつかあります。どうすればいいですか?さらに、そのようなインスタンスが作成されるたびに完全に新しいコンテキストが作成されますか、それとも何かが足りませんか?

それに対するより良い解決策はありませんか?

どんな助けでも大歓迎です。

4

1 に答える 1

8

ここでは、アクティブ化メールの送信アクションはビジネスレイヤーの一部ではないと思います。ここでのドメインロジックはアカウントアクティブ化アクションであり、そのロジックの一部は DomainObjectwith name Account( activate()method ) に存在する必要があります。アクティブ化電子メールの送信アクションは、infrastructureまたはapplicationレイヤーの一部です。

サービスは、アカウントの有効化リクエストを処理し、ビジネスレイヤーとその他を接続するオブジェクトです。サービスは、指定されたアカウントを受け取り、それらをアクティブ化し、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);
 }

}

私が提案できる次のステップは、ビジネス層とインフラストラクチャ層を完全に分離することです。これは、ビジネスイベントを紹介することで入手できます。サービスは、電子メールを送信するためにアクションを実行する必要がなくなり、アカウントの有効化について他のレイヤーに通知するイベントを作成します。

Spring には、イベントを操作するための 2 つのツールがApplicationEventPublisherありApplicationListenerます。

ドメインイベントを発行するサービスの短い例:

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

これで、別のアクティベーション タイプ、ロギング、その他のインフラストラクチャ サポートを変更せずに追加して、ドメイン (ビジネス) レイヤーを汚染することができます。

春のイベントの詳細については、ドキュメントを参照してください。

于 2012-07-30T10:39:03.807 に答える