论坛首页 Java企业应用论坛

再次小结领域模型的种种观点

浏览 146170 次
该帖已经被评为精华帖
作者 正文
   发表时间:2005-12-16  
To downpour:

doLogin放到service这种方法的褒贬我没什么看法

但是 user.logon() 这种模式更能被我的所在team所理解,无他仅此而已

同时 domain object也是主要活跃于service层的,和构架没有什么关系。

你的关于层次架构方面的观点我无异议,我也是这样做的 cheers.
0 请登录后投票
   发表时间:2005-12-16  
to: robbin
引用
三、充血模型
充血模型和第二种模型差不多,所不同的就是如何划分业务逻辑,即认为,绝大多业务逻辑都应该被放在domain object里面(包括持久化逻辑),而Service层应该是很薄的一层,仅仅封装事务和少量逻辑,不和DAO层打交道。

请注意你的这句话:"不和DAO层打交道".
让后请看http://jroller.com/page/habuma?entry=spring_2_0_vs_the中,
public class CustomerServiceImpl implements CustomerService {
  public CustomerServiceImpl(); {}
  
  public void copyAndTweakCustomer(Integer id); {
    Customer original = dao.load(id);;
    
    Customer duplicate = new Customer();;
    duplicate.setId(original.getId(); + 1);;
    duplicate.setName(original.getName(););;
    
    original.setName("Michael Walls");;
    
    original.save();;
    duplicate.save();;
  }
  
  private CustomerDao dao;
  public void setDao(CustomerDao dao); {
      this.dao = dao;
  }
}


这里还有这么一句:
引用

You'll notice that the service object is also injected with a CustomerDao. This is so that it can load a previously-persisted Customer. This illustrates an important point: Just because the domain object is now primarily responsible for its own persistence, that does not mean that service objects can't also access the DAO to load previously-persisted instances.


似乎service 还和DAO层打交道.
0 请登录后投票
   发表时间:2005-12-16  
Readonly 写道
robbin 写道
好吧,那么我是web程序员,我从页面传一个id过来,要先load一下该Account,显示account的信息。那么请问:你提供给我什么API?是
account.getAccountById(id);
还是
accountService.getAccountById(id);
还是
accountDao.getAccountById(id);
?


new Account(id);

俄没接触过对象数据库.
假如我用的是对象数据库,无疑new Account(id);是适合的.
o\r maping
o\o maping
0 请登录后投票
   发表时间:2005-12-17  
Partech,看到这么一些代码:

public class AccountService {
           private AccountDAO dao;
           
           public void createAccount(Account ac);{
                     dao.save(ac);;
           }
            
            public void removeAccount(Account ac);{
                     dao.remove(ac);;
           }
          public void updateAccount(Account ac);{
                     dao.update(ac);;
           }
            
}


我不觉得它有多可爱,我横看竖看,前看后看,左看右看,上看下看,可还是看不出这个Service除了为获得事务外,他还做了什么东西。
如果他有一些逻辑方法里面包含一些有意义的业务逻辑,那我无话可说,但是我所看到很大一个比例的方法都是这样类似的delegate的代码。
很多人还喜欢先写Service的Interface ,再来写这些delegate代码,看着更是感到可爱。

你认为我的理解有什么不对吧? 我很乐意你能够指出我的错误... 

0 请登录后投票
   发表时间:2005-12-17  
一个完整的annotation-free的解决方案。不喜欢factory的同学们可以看看这个方案如何:
http://docs.codehaus.org/display/YAN/All+About+Post+Instantiation
0 请登录后投票
   发表时间:2005-12-17  
downpour 写道
我是比较同意robbin的观点的,举个登录的例子:

EmployeeService的实现:
    /* (non-Javadoc);
     * @see com.bearingpoint.gdc.service.EmployeeService#doLogin(java.lang.String, java.lang.String);
     */
    public Employee doLogin(String name, String password); throws ObjectNotFoundException, PasswordNotMatchException {
        Employee employee = null;
        List result = employeeDAO.getEmployeeByName(name);;
        if(result.size(); == 0);
            throw new ObjectNotFoundException();;
        else {
            employee = (Employee);result.get(0);;            
            if(!employee.getPassword();.equals(password););
                throw new PasswordNotMatchException();;
        }
        return employee;
    }


DAO的实现:
    /* (non-Javadoc);
     * @see com.bearingpoint.gdc.dao.EmployeeDAO#getEmployeeByName(java.lang.String);
     */
    public List getEmployeeByName(String name); {
        String querySentence = "FROM Employee employee WHERE employee.name = :name";
        Query query = getSession();.createQuery(querySentence);;
        query.setParameter("name", name);;
        return query.list();;
    }


Action更简单:
/* (non-Javadoc);
     * @see com.opensymphony.xwork.Action#execute();
     */
    public String execute(); throws Exception {        
        employee = employeeService.doLogin(employee.getName();, employee.getPassword(););;
        
        //put the employee into session
        ServletActionContext.getContext();.getSession();.put("currentEmployee", employee);;
        
        return SUCCESS;
    }


结构层次很清晰,DAO就负责数据库操作,Service层处理逻辑。万一你的业务逻辑发生扩展和变化,也只要修改和扩展你的Service实现,与其他层次无关。同时,Service层总是接受事务的控制。

按照firebody的观点,莫非我的doLogin的逻辑要写在我的Employee类里面?然后new Employee(String name, String password) throw xxxException?这太恶心了。


我仅仅说了1,你就用你自己的思路往前说出了3,4,5.... 。而这些并不是我所说的,按照你的思路下的产物也不一定是我所说的思路的结果。
另外指出一点: employee.login() 这个方法为什么要放在Employee身上? Rich Domain Model != All is Entity Model . 希望你能够理解我的意思,SecurityService 一样会存在,也一样会在他身上存在验证用户权限的方法 ,
还有另外: 看到你的这行代码:
if(!employee.getPassword();.equals(password););
                throw new PasswordNotMatchException();; 


不如改成这个吧:
employee.authenticate(password);


贫血模型用多了,看来很多代码也会变味的。 赫赫。   
0 请登录后投票
   发表时间:2005-12-17  
firebody 写道
Partech,看到这么一些代码:

public class AccountService {
           private AccountDAO dao;
           
           public void createAccount(Account ac);{
                     dao.save(ac);;
           }
            
            public void removeAccount(Account ac);{
                     dao.remove(ac);;
           }
          public void updateAccount(Account ac);{
                     dao.update(ac);;
           }
            
}


我不觉得它有多可爱,我横看竖看,前看后看,左看右看,上看下看,可还是看不出这个Service除了为获得事务外,他还做了什么东西。
如果他有一些逻辑方法里面包含一些有意义的业务逻辑,那我无话可说,但是我所看到很大一个比例的方法都是这样类似的delegate的代码。
很多人还喜欢先写Service的Interface ,再来写这些delegate代码,看着更是感到可爱。

你认为我的理解有什么不对吧? 我很乐意你能够指出我的错误... 


嗯,如果你的ServiceLayer接口里传递的参数包含DomainObject那么,ServiceLayer确实少了很多职责。UI层直接修改DomainObject是否也算是业务逻辑呢?那么UI层还能叫UI层吗?业务层还能叫业务层吗?
Service被看作Domain层和UI层的接口/外观,会具有适配两者的职责,通常我们不会把DomainObject直接传递到UI层,总是使用DTO,目前看看使用通用的SDO行不行,甚至异常也需要转换。如果使用Aspect来管理事务,Service里面的代码就很干净了。
对于查询操作:
public class AccountService{
      private IAccountRepository accountRepository;
      private IAccountInfoAssembler accountInfoAssembler;

      public AccountInfo getAccountInfo(String accountCode);{
                Account account = accountRepository.findByCode(accountCode);;
          return  accountInfoAssembler.create(account);;
     }
    
}

对于更新操作:
public class AccountService{
      private IAccountRepository accountRepository;
      private IAccountInfoAssembler accountInfoAssembler;

      public void createAccount(String Code,String Name,...);{
               IAct act = new CreateAccountAct(code,name,....);;
                act.run();;
     }
}

异常转换的处理和事务控制都可以通过Aspect达成。
0 请登录后投票
   发表时间:2005-12-17  
partech 写道

嗯,如果你的ServiceLayer接口里传递的参数包含DomainObject那么,ServiceLayer确实少了很多职责。
Service被看作Domain层和UI层的接口/外观,会具有适配两者的职责,通常我们不会把DomainObject直接传递到UI层,总是使用DTO,目前看看使用通用的SDO行不行,甚至异常也需要转换。如果使用Aspect来管理事务,Service里面的代码就很干净了。
对于查询操作:
public class AccountService{
      private IAccountRepository accountRepository;
      private IAccountInfoAssembler accountInfoAssembler;

      public getAccountInfo(String accountCode);{
                Account account = accountRepository.findByCode(accountCode);;
          return  accountInfoAssembler.Create(account);;
     }
    
}

对于更新操作:
public class AccountService{
      private IAccountRepository accountRepository;
      private IAccountInfoAssembler accountInfoAssembler;

      public createAccount(String Code,String Name,...);{
               IAct act = new CreateAccountAct(code,name,....);;
                act.run();;
     }
}

异常转换的处理和事务控制都可以通过Aspect达成。

哦,你所说的DTO--->Service --->Domain Model。
Service的职责确实多了,这样的Service确实有存在的必要的。
不过流行的ognl可以很容易的消除DTO,这样你需要写的代码会更少。
不过要在项目中将ognl融合进来,还需要一定精巧的设计。
webwork可是作了很多工作的,从你提到的思路来看,其实ww的Controller将承担了你所提到的Service一部分职责。

ognl是可以很好的用在Swing UI上面的。
0 请登录后投票
   发表时间:2005-12-17  
如果不需要DTO,而是直接透传DomainObject,DomainObject可以在UI层更改。
我的问题是如何界定DomainObject那些属性,可以在UI改,那些必须放到业务层更改?区分的原则是什么?
如果我可以在UI中更改DomainObject,是否我可以把所有的有关更改DomainObject的业务逻辑放到UI?同时我是否可以把所有需要检查的Rule对象也传递到UI。那么业务层中还能剩下什么?业务层还能叫业务层吗?
0 请登录后投票
   发表时间:2005-12-17  
firebody 写道
Partech,看到这么一些代码:

public class AccountService {
           private AccountDAO dao;
           
           public void createAccount(Account ac);{
                     dao.save(ac);;
           }
            
            public void removeAccount(Account ac);{
                     dao.remove(ac);;
           }
          public void updateAccount(Account ac);{
                     dao.update(ac);;
           }
            
}


我不觉得它有多可爱,我横看竖看,前看后看,左看右看,上看下看,可还是看不出这个Service除了为获得事务外,他还做了什么东西。
如果他有一些逻辑方法里面包含一些有意义的业务逻辑,那我无话可说,但是我所看到很大一个比例的方法都是这样类似的delegate的代码。
很多人还喜欢先写Service的Interface ,再来写这些delegate代码,看着更是感到可爱。

你认为我的理解有什么不对吧? 我很乐意你能够指出我的错误... 



这样的代码的确不怎么可爱,除了获得事务,它也的确什么都没有做。但是问题是,绝大多数的情况,逻辑方法中会包含一些有意义的逻辑。

比如说,在save之前,看看它在数据库中是否已经存在了。难道你不认为这是一种逻辑嘛?

登录的例子是我随手写的,我承认employee.authenticate(password)更加OO。而事实上,很多状态维护的代码也应该被写在domain object里面。

像Hibernate里面的父子关系的例子中,为父亲添加一个儿子,总是这么写:

public void addChild(Child c); {
    c.setParent(this);;
    children.add(c);;
}


像这种丝毫不依赖于持久化的代码,我绝对会放在Parent对象里面,而不是Service层。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics