IT tutorials
 
Database
 

Oracle Coherence 3.5 : Implementing Domain Objects - Domain model building blocks (part 3) - Factories, Repositories

1/3/2013 11:40:50 AM
- Free product key for windows 10
- Free Product Key for Microsoft office 365
- Malwarebytes Premium 3.7.1 Serial Keys (LifeTime) 2019

3. Factories

When we discussed creation of entity instances I mentioned that I prefer a static factory method to a direct use of a constructor. In most cases, either of those two options will be all you need. However, in some cases the creational logic for an entity might be complex, in which case implementing a factory as a separate class might be the best approach.

In most cases, implementing a factory as a separate class is not very different from the static factory method approach. For example, the following factory class is functionally equivalent to the static factory method we created earlier:

public class AccountFactory {
private static IdentityGenerator<Long> s_idGen =
SequenceGenerator.create("account.id", 20);
public Account createAccount(Customer customer,
String description,
Currency currency) {
return new Account(s_idGen.generateIdentity(),
customer.getId(),
description,
new Money(0, currency));
}
}

However, the fact that the factory is now a separate class opens up some interesting possibilities. For example, we could get rid of the hardcoded SequenceGenerator dependency and use Spring to configure the factory instance:

public class AccountFactory {
private IdentityGenerator<Long> m_idGen;
public AccountFactory(IdentityGenerator<Long> idGen) {
m_idGen = idGen;
}
public Account createAccount(Customer customer,
String description,
Currency currency) {
return new Account(m_idGen.generateIdentity(),
customer.getId(),
description,
new Money(0, currency));
}
}

The following Spring configuration could then be used to wire the AccountFactory instance:

<bean id="accountFactory" class="domain.AccountFactory">
<constructor-arg>
<bean class="c.s.c.identity.sequence.SequenceGenerator">
<constructor-arg value="account.id"/>
<constructor-arg value="20"/>
</bean>
</constructor-arg>
</bean>

That way you can let Spring manage dependencies and will be able to provide a fake or mock for the identity generator within unit tests, which alone might be a good enough reason to take this extra step.

4. Repositories

The factories are useful when we need to create new instances of domain objects, but in many cases we simply need to retrieve the existing instances. In order to accomplish that, we can use a repository.

According to Domain Driven Design, a repository can be thought of as an unlimited, memory-backed object store containing all objects of a specific type. If that definition reminds you of a Coherence cache, you are not alone-a Coherence cache is a great object repository indeed.

Ideally, the repository interface should be completely independent of the underlying infrastructure and should be expressed in terms of domain objects and their attributes only. For example, we could define AccountRepository like this:

public interface AccountRepository {
Account getAccount(Long id);
Collection<Account> getAccounts(Collection<Long> accountIds);
void save(Account account);
}

As you can see, the interface is completely Coherence agnostic, and can be implemented for pretty much any data source. A Coherence implementation might look like this:

public class CoherenceAccountRepository
implements AccountRepository {
private static final NamedCache s_accounts = CacheFactory.getCache("accounts");
public Account getAccount(Long id) {
return (Account) s_accounts.get(id);
}
public Collection<Account> getAccounts( Collection<Long> accountIds) {
return (Collection<Account>)
s_accounts.getAll(accountIds).values();
}
public void save(Account account) {
s_accounts.put(account.getId(), account);
}
}


					  

What you will quickly notice if you start implementing repositories this way is that basic CRUD operations tend to repeat within every repository implementation, so it makes sense to pull them up into an abstract base class in order to avoid implementing them over and over again:

public abstract class AbstractCoherenceRepository<K, V extends Entity<K>> {
public abstract NamedCache getCache();
public V get(K key) {
return (V) getCache().get(key);
repository, domain model building blocksabstract base class}
public Collection<V> getAll(Collection<K> keys) {
return getCache().getAll(keys).values();
}
public void save(V value) {
getCache().putAll(
Collections.singletonMap(value.getId(), value));
}
public void saveAll(Collection<V> values) {
Map batch = new HashMap(values.size());
for (V value : values) {
batch.put(value.getId(), value);
}
getCache().putAll(batch);
}
}

This abstract base class for our repository implementations uses generics to specify the key and value type for the cache that the repository is used to access, and constrains value type to the types that implement the Entity interface we defined earlier. This allows us to implement the save and saveAll methods as mentioned earlier, because we can obtain the cache key for any entity by calling its getId method.

NamedCache.put versus NamedCache.putAll

One thing to note is the implementation of the save method. While I could've just made a simple call to a NamedCache.put method, I have chosen to use putAll instead, in order to improve performance by eliminating one network call.

The reason for this is that the NamedCache.put method strictly follows the contract defined by the Map interface and returns the old value from the cache. This is fine when you are accessing a map in-process or need the old value, but in this case neither is true and using put would simply increase the latency.


Our CoherenceAccountRepository implementation now simply becomes:

public class CoherenceOrderRepository
extends AbstractCoherenceRepository<Long, Account>
implements AccountRepository {
private static final NamedCache m_accounts = CacheFactory.getCache("accounts");
public NamedCache getCache() {
return m_accounts;
}
public Account getAccount(Long id) {
return super.get(id);
}
public Collection<Account> getAccounts( Collection<Long> accountIds) {
return super.getAll(accountIds);
}
}


					  

This concludes our coverage of different types of data objects within a domain model and how to map them to Coherence caches. For the most part, you should now know enough to be able to implement your data objects and put them into the cache.

One thing you might've noticed is that, aside from the repository implementation, none of the domain classes we implemented thus far have any dependency on or knowledge of Coherence, despite the somewhat leaky repository abstraction. This is an example of what DDD calls persistence ignorance (PI) and is extremely important as it allows us to unit test our domain model objects in isolation.

For the most part, you can use the domain objects we implemented in this section without any modifications. However, there are several important considerations that we haven't discussed yet that you need to understand in order to implement your data objects (entities and aggregates) in an optimal way.

 
Others
 
 
 
Top 10
 
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 2) - Wireframes,Legends
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 1) - Swimlanes
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Formatting and sizing lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Adding shapes to lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Sizing containers
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 3) - The Other Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 2) - The Data Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 1) - The Format Properties of a Control
- Microsoft Access 2010 : Form Properties and Why Should You Use Them - Working with the Properties Window
- Microsoft Visio 2013 : Using the Organization Chart Wizard with new data
Technology FAQ
- Is possible to just to use a wireless router to extend wireless access to wireless access points?
- Ruby - Insert Struct to MySql
- how to find my Symantec pcAnywhere serial number
- About direct X / Open GL issue
- How to determine eclipse version?
- What SAN cert Exchange 2010 for UM, OA?
- How do I populate a SQL Express table from Excel file?
- code for express check out with Paypal.
- Problem with Templated User Control
- ShellExecute SW_HIDE
programming4us programming4us