Objectopia

Persistent Strategies

Posted by Chris Burnley on March 22, 2009

I’ve just finished working on a cash management system. The core of what the system does is listen to messages produced by various sources and record a transaction (i.e. a debit and a credit) between two accounts.

For example, the system will listen to trade messages produced by our trading system and charge a trade fee to the client. This involves debiting the client and crediting the Fee house account.

This seems innocent enough, but to create a transaction you must have a reference to each of these accounts.

The client’s account is easy enough to find as all the required information is supplied in the trade message. But what about the house account ? How does the system find an instance of the house Account ?

One could do something like this, store the account number in a constant somewhere:

Account account = accountService.getAccount(FEE_HOUSE_ACCOUNT_NUMBER);

// create Transaction with client and house account

This is pretty bad IMO because there is duplication and “hard coding” ( even if it is in a properties file) of what house account numbers there are.

If you didn’t want to store the account number in code (or in a properties file which is almost as bad) you could add it to the static data for that transaction type:

@Entity
class TransactionType {
    String name;
    Account creditAccount; // this could be null to indicate that the account is based on the message
    Account debitAccount; // this could be null to indicate that the account is based on the message
    //...
}

then you would just find the TransactionType and the get the credit or debit account.

This would work, but it is very specific, since sometimes we may want to find the debit / credit account in a different way (e.g. “find the loan account associated with the client’s cash account”).

Enter the Persistent Strategy.

Basically, the idea is that rather than store links directly to Accounts in your static data, store a Strategy to obtain the right Account.

@Entity
public class TransactionType {</code>

    private String type;

    @ManyToOne
    private AccountAllocationStrategy toAccountStrategy;

    @ManyToOne
    private AccountAllocationStrategy fromAccountStrategy;
}

@Entity
@Inheritance
public abstract class AccountAllocationStrategy {
    public abstract Account getAccount(Transaction transaction);
}

What we’ve done is added a strategy for find the from / to account and we can have specific implementations:

@Entity
public class FixedAccountAllocation extends AccountAllocationStrategy {

    @ManyToOne
    private Account account;

    public Account getAccount(Transaction transaction) {
        return account;
    }
}

@Entity
public class InvestorAccountAllocation extends AccountAllocationStrategy {

    @Override
    public Account getAccount(Transaction transaction) {
        return transaction.getInvestorAccount();
    }
}

(there are a few more implementations I’ve left out for brevity).

You could achieve a similar effect by using a code of some sort (e.g. an enum) to denote the strategy and look up the strategy instance via Spring, but I like this better since it is more transparent and doesn’t require involving other frameworks. The major problem with the Spring approach is you’ve still got to specify the account numbers somewhere in your Spring context file which is duplication (once in the Spring file, once in the database) which, we all know, is bad :)

It might seem like abusing entities or the domain model but it is a really powerful pattern. Think of these entities as your rule domain. JPA makes mapping entities really easy and the number of strategies are finite so you can be quite creative in your mapping and inheritance hierarchies. You can also fully cache the strategy entities so performance will not be an issue.

We use this pattern in a few places in the system and it has made the code much cleaner and maintainable.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

 
Follow

Get every new post delivered to your Inbox.