Is it a good idea to "migrate business logic code into our domain model"?
I am reading Hibernate in Action and the author suggests to move business logic into our domain models (p. 306). For instance, in the example presented by the book, we have three entities named Item
, Bid
, and User
and the author suggests to add a placeBid(User bidder, BigDecimal amount)
method to the Item
class.
Considering that usually we have a distinct layer for business logic (e.g. Manager
or Service
classes in Spring) that among other things control transactions, et开发者_如何转开发c. is this really a good advice? Isn't it better not to add business logic methods to our entities?
Thanks in advance.
As said
We have a distinct layer for business logic (usually called Service layer)
Domain-Driven-Design (DDD) states you should put business logic inside your domain model. And, believe me, it is really good. As said by POJO in Action book about Service layer
- It is Use Case driven
- It can define Transaction boundaries
Before
@Service
public class BidServiceImpl implements BidService {
@Autowired
private ItemRepository itemRepository;
public void placeBid(Integer itemId, User bidder, BigDecimal amount) {
Item item = itemRepository.getById(itemId);
if(amount.compareTo(new BigDecimal("0.00")) <= 0)
throw new IllegalStateException("Amount must be greater than zero");
if(!bidder.isEnabled())
throw new IllegalStateException("Disabled bidder");
item.getBidList().add(new Bid(bidder, amount));
}
}
After
@Service
public class BidServiceImpl implements BidService {
@Autowired
private ItemRepository itemRepository;
public void placeBid(Integer itemId, User bidder, BigDecimal amount) {
// itemRepository will retrieve a managed Item instance
Item item = itemRepository.getById(itemId);
item.placeBid(bidder, amount);
}
}
Your domain logic is show as follows
@Entity
public class Item implements Serializable {
private List<Bid> bidList = new ArrayList<Bid>();
@OneToMany(cascade=CascadeType.ALL)
public List<Bid> getBidList() {
return this.bidList;
}
public void placeBid(User bidder, BigDecimal amount) {
if(amount.compareTo(new BigDecimal("0.00")) <= 0)
throw new IllegalStateException("Amount must be greater than zero");
if(!bidder.isEnabled())
throw new IllegalStateException("Disabled bidder");
/**
* By using Automatic Dirty Checking
*
* Hibernate will save our Bid
*/
item.getBidList().add(new Bid(bidder, amount));
}
}
When using Domain-Driven-Design, your business logic lives in the right place. But, sometimes, it could be a good idea to define your business logic inside your Service layer. See here why
One of the most quoted articles on this is:
"The Anemic Domain Model" by Martin Fowler. Well worth reading: http://martinfowler.com/bliki/AnemicDomainModel.html
The general gist is if your domain model is purely data with no behaviour then you have lost many of the benefits of OO design.
or to quote:
"In general, the more behavior you find in the services, the more likely you are to be robbing yourself of the benefits of a domain model. If all your logic is in services, you've robbed yourself blind."
Personally I love the anemic model -- data is data, code is code; but there are exceptions.
It comes down to 'density': If you have a great number of services which interact with a few domain objects; it makes sense to put some of the common business logic in your domain model, it thus becomes part of the service. If you have a few services which interact with lots of domain objects then favor the anemic model over the rich domain objects.
I have found that if I use my domain objects in multiple contexts (e.g. I use the same domain objects on the client side and on the service side) that business logic often gets in the way -- since it must be applicable in all contexts.
精彩评论