How to handle injecting dependencies into rich domain models?
In a web server project with a rich domain model (application logic is in the model, not in the services) how do you handle injecting the dependencies into the model objects? What are your experiences?
Do you use some form of AOP? Like Springs @Configurable annotation? Load time or build time weawing? Problems you encountered?
Do you use manual injection? Then how do you handle different instantia开发者_Go百科tion scenarios (creating of the objects through an library [like Hibernate], creating objects with "new" ...)?
Or do you use some other way of injecting the dependencies?
We use Spring's @Configurable (along with regular new operator) which works like a charm. No more anemic domain models. Finally, this is much more object oriented design, isn't it:
Person person = new Person(firstname, lastname);
// weird
peopleService.save(person);
// good (save is @Transactional)
person.save();
Mail mail = new Mail(to, subject, body);
// weird
mailService.send(mail);
// good (send is @Transactional)
mail.send();
We haven't done any performance comparison though. So far, we simply haven't felt the need to do so.
EDIT: that's how the person class would look like:
@Configurable("person")
public class Person {
private IPersonDAO _personDAO;
private String _firstname;
private String _lastname;
// SNIP: some constructors, getters and setters
@Transactional(rollbackFor = DataAccessException.class)
public void save() {
_personDAO.save(this);
}
@Transactional(readOnly = true)
public List<Role> searchRoles(Company company) void{
return _personDAO.searchRoles(this, company);
}
// it's getting more interesting for more complex methods
@Transactional(rollbackFor = DataAccessException.class)
public void resignAllRoles(Company company) {
for (Role role : searchRoles(company)) {
role.resign();
}
}
}
// the implementation now looks like this
personService.getPerson(id).resignAllRoles(company);
// instead of this
roleService.resignAll(personService.searchRoles(personService.getPerson(id), company));
And that's the Spring config:
<context:spring-configured />
<bean id="person" class="org.example.model.Person" lazy-init="true">
<property name="personDAO" ref="personDAO" />
</bean>
Note: as you see, there are still services around, e.g. to search for objects (personService.getPerson(id)) but all methods that operate on a passed object (e.g. a person) are moved to that class itself (i.e. person.save() instead of personService.save(person)). The method itself stays the same and works with any underlying data access layer (pure JDBC, Hibernate, JPA, ...). It has simply moved where it belongs.
To keep my domain objects clean I avoid using injection on the entities/aggregates/value objects and rather put those in the services or repositories if needed.
For this we used normal Spring constructor injection to ease testing.
If you need to inject something into your entities one suggestion could be to write a builder or factory and inject what you needed there instead.
You can also check the link below, which can help out a lot.
A Pragmatic View on Software Architecture and the Rich Domain Model describes where the Rich Domain Model and Software Architecture meet.
Furthermore it describes how to configure, implement and junit this view with following techniques, frameworks and api's:
- Spring; to make life easier for a developer
- JPA; for Object Relational Mapping
- AspectJ; to fully experience the Rich Domain Model
- JUnit; for integration testing of your Rich Domain Model
http://www.ruimtefotografie.org/forum/viewtopic.php?f=32&t=193
精彩评论