如果 class 只代表而不做任何其他事情,它有什么用?
What is a class good for if it only delegates and does nothing else?
这里的例子摘自书本:Professional Java Development with the Spring Framework.
在AOP章节中,我们以一个AccountManager的实现为例:
public class AccountManagerImpl implements AccountManager {
private MailSender mailSender;
private SimpleMailMessage message;
private AccountDao accountDao;
public void setMailSender(MailSender mailSender) {
this.mailSender = mailSender;
}
public void setMessage(SimpleMailMessage message) {
this.message = message;
}
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
private void sendMail(Exception ex) {
SimpleMailMessage msg = new SimpleMailMessage(this.message);
msg.setText("Encountered exception " + ex.getMessage());
this.mailSender.send(msg);
}
public Account getAccount(String accountId) throws AccountNotFoundException, DataAccessException {
try {
return this.accountDao.findAccount(accountId);
} catch (AccountNotFoundException ex) {
sendMail(ex);
throw ex;
} catch (DataAccessException ex) {
sendMail(ex);
throw ex;
}
}
public void createAccount(Account account) throws DataAccessException, {
try {
if (isInvalid(account)) {
throw new InvalidAccountException(account);
this.accountDao.saveAccount(account);
} catch(IOException ex){
sendMail(ex);
throw ex;
} catch(DataAccessException ex){
sendMail(ex);
throw ex;
}
}
}
}
然后解释了面向方面编程的所有优点,进行了一些配置以将 sendMail(ex)
移动到一个方面,我们最终得到:
public class AccountManagerImpl implements AccountManager {
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
public Account getAccount(String accountId)
throws AccountNotFoundException, DataAccessException {
return this.accountDao.findAccount(accountId);
}
public void createAccount(Account account) throws DataAccessException {
this.accountDao.saveAccount(account);
}
}
引自本书本身:
The result is a major improvement. The AccountManager is purely
responsible for account management, making the code much simpler and
easier to read and maintain. The exception notification mechanism is
cleanly modularized so that it can be maintained separately from
business logic. For example, one developer can now revise the
exception notification policy without the need to modify large numbers
of files that would be affected in the traditional approach.
在我看来,AccountManagerImpl 之前实际上是一个 Manager,而第二个示例只是一场灾难。
正如在实施的第二个版本中所看到的,管理器 class 根本没有做任何事情,而是将所有事情委托给一个 AccountDao
。
我的具体问题是:为什么要有这个实现(第二版)?我们也可以将 Aspect 应用于 AccountDao
,不是吗?
我同意重构后管理器的核心功能看起来没有说服力。但其原因可能仅仅是作者没有花太多时间寻找更好的例子。
方面的要点是:提取可以在不同 classes 中找到的横切功能。换句话说:您发现一个或多个 classes 花费代码做一些并不真正适合每个 class 的核心职责的事情。然后将此 "non core functionality" 抽象为方面 - 允许您转向 AOP 工具。这样您就可以通过让工具将相应的代码移动到方面来整理您的核心业务逻辑。
如果管理器 class 是一个外观,那么它的目的是隐藏其成员交互的复杂性。在你的例子中,它有点太简单了,所以好处并不明显。但是考虑到对 DAO 的调用不是那么直接(需要一些锅炉代码),那么复杂性被管理器隐藏起来是件好事 class。或者假设 DAO 需要与其他对象进行一些交互,那么这种复杂性也被管理器隐藏了 class。对于外部客户端调用很简单。
这里的例子摘自书本:Professional Java Development with the Spring Framework.
在AOP章节中,我们以一个AccountManager的实现为例:
public class AccountManagerImpl implements AccountManager {
private MailSender mailSender;
private SimpleMailMessage message;
private AccountDao accountDao;
public void setMailSender(MailSender mailSender) {
this.mailSender = mailSender;
}
public void setMessage(SimpleMailMessage message) {
this.message = message;
}
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
private void sendMail(Exception ex) {
SimpleMailMessage msg = new SimpleMailMessage(this.message);
msg.setText("Encountered exception " + ex.getMessage());
this.mailSender.send(msg);
}
public Account getAccount(String accountId) throws AccountNotFoundException, DataAccessException {
try {
return this.accountDao.findAccount(accountId);
} catch (AccountNotFoundException ex) {
sendMail(ex);
throw ex;
} catch (DataAccessException ex) {
sendMail(ex);
throw ex;
}
}
public void createAccount(Account account) throws DataAccessException, {
try {
if (isInvalid(account)) {
throw new InvalidAccountException(account);
this.accountDao.saveAccount(account);
} catch(IOException ex){
sendMail(ex);
throw ex;
} catch(DataAccessException ex){
sendMail(ex);
throw ex;
}
}
}
}
然后解释了面向方面编程的所有优点,进行了一些配置以将 sendMail(ex)
移动到一个方面,我们最终得到:
public class AccountManagerImpl implements AccountManager {
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
public Account getAccount(String accountId)
throws AccountNotFoundException, DataAccessException {
return this.accountDao.findAccount(accountId);
}
public void createAccount(Account account) throws DataAccessException {
this.accountDao.saveAccount(account);
}
}
引自本书本身:
The result is a major improvement. The AccountManager is purely responsible for account management, making the code much simpler and easier to read and maintain. The exception notification mechanism is cleanly modularized so that it can be maintained separately from business logic. For example, one developer can now revise the exception notification policy without the need to modify large numbers of files that would be affected in the traditional approach.
在我看来,AccountManagerImpl 之前实际上是一个 Manager,而第二个示例只是一场灾难。
正如在实施的第二个版本中所看到的,管理器 class 根本没有做任何事情,而是将所有事情委托给一个 AccountDao
。
我的具体问题是:为什么要有这个实现(第二版)?我们也可以将 Aspect 应用于 AccountDao
,不是吗?
我同意重构后管理器的核心功能看起来没有说服力。但其原因可能仅仅是作者没有花太多时间寻找更好的例子。
方面的要点是:提取可以在不同 classes 中找到的横切功能。换句话说:您发现一个或多个 classes 花费代码做一些并不真正适合每个 class 的核心职责的事情。然后将此 "non core functionality" 抽象为方面 - 允许您转向 AOP 工具。这样您就可以通过让工具将相应的代码移动到方面来整理您的核心业务逻辑。
如果管理器 class 是一个外观,那么它的目的是隐藏其成员交互的复杂性。在你的例子中,它有点太简单了,所以好处并不明显。但是考虑到对 DAO 的调用不是那么直接(需要一些锅炉代码),那么复杂性被管理器隐藏起来是件好事 class。或者假设 DAO 需要与其他对象进行一些交互,那么这种复杂性也被管理器隐藏了 class。对于外部客户端调用很简单。