In this article, I want to use a real (albeit simplified) example to show an application of the Decorator pattern in Dynamics AX and the related refactoring.
The requirement was something like this: “During the posting of an Expense Report (Expense Management module), find the maximum allowed amount, lower the transaction amount to this limit and create another transaction for the over-limit amount to another account”. There were some parameters, of course, but they’re not important here.
Virtually all posting logic is implemented in the post() method of the TrvPost class (static method with 341 lines – and this is not the only thing which I would say against this method and the whole Trv* module). Besides other code duplicities, transaction posting to general ledger is repeated six times in this method. If I placed the requested branching in each of these occurrences, the problem with duplicities would become at least twice as bad. Moreover, another transaction splitting (based on a different logic) is going to be implemented later. A refactoring is obviously necessary.
Note: Each modification of a standard code in Dynamics AX entails certain expenses – above all it complicates upgrades to higher versions. So is it proper to do such a refactoring?
Certainly YES, if it is needed for a correct implementation. If I don’t like some part of a code, but I’m able to use it without troubles, I shoudn’t just “fix it”. But this attempt to avoid unnecessary modifications cannot be an excuse for writing a poor quality and unmaintainable code. In the example above, I could easily end with a method with 600 lines and dozens of duplicate postings.
OK, a refactoring then. The first and unavoidable step is a code separation to classes and methods. This decomposition can be done in several ways, however is it reasonable to create one class for posting of the whole expense report, which will be responsible for the way of posting of individual lines, and another simple class for line posting. In addition, you can extract a creation of LedgerJournalTable to a separate method, convert SQL statements to parametrized queries etc. The result should generally looks like an object-oriented code. 🙂
I ended with a relatively robust class TrvExpTablePost (18 methods) and a trivial class TrvExpTransPost (5 methods; a single public worker method only).
Lots of people don’t fully understand how is refactoring important and why is it needed to think about refactoring separately, not to mix it with an implementation of new features. We’ve just got a different code, which works identically as the original code (it can be proven by original tests – if they exist – including automated tests). And I’m going to show now how small amount of code we actually need to add.
Now is the time for the mentioned Decorator pattern. If you’ve never heard about it, get a quick introduction here, for instance. Many books also exist about design patterns.
The Decorater essentially allows to wrap additional behaviour around an existing object without changing the way of using of this object.
We will implement the decorator as a separate class, containing the decorated object (TrvExpTransPost in my case) as its member variable and having the same public interface (the easiest way to guarantee that is to use an interface
type, implemented by both the decorated class and the decorator).
My implementation of the interface looks like this:
interface TrvExpPostTransProvider { void postTrans(TrvExpTrans _trvExpTrans) //TrvExpTablePost is a class for posting of the whole expense report and it has //some information needed for transaction postings void setExpTablePost(TrvExpTablePost _expTablePost) void setLedgerJournalTable(LedgerJournalTable _ledgerJournalTable) }
That was easy. Now I’ll create an abstract class, implementing this interface, which provides a default implementation for both set*() methods.
abstract class TrvExpPostTransDecorator implements TrvExpPostTransProvider { //Decorated object TrvExpPostTransProvider decoratedPosting; void new(TrvExpPostTransProvider _posting) { decoratedPosting = _posting; } abstract public void postTrans(TrvExpTrans _trvExpTrans){} public void setExpTablePost(TrvExpTablePost _expTablePost) { decoratedPosting.setExpTablePost(_expTablePost) } public void setLedgerJournalTable(LedgerJournalTable _ledgerJournalTable) { decoratedPosting.setLedgerJournalTable(_ledgerJournalTable) } }
The constructor receives an object of the interface type, so we can decorate not only the TrvExpPostTrans class, but also another decorator. Set*() methods simply hand the values on (however the decorator could process these values, if it needed them) and the postTrans() method must be explicitly implemented by each decorator.
We still haven’t added any new behaviour, so let’s go to it now. I’ll create an additional class:
class TrvExpPostMySplitDecorator extends TrvExpPostTransDecorator { public void postTrans(TrvExpTrans _trvExpTrans) { //pseudocode if (is the transaction to be splitted) { set the transaction amount to the limit amount and post create and post a new transaction with the over-limit amount } else { post the transaction } } }
The posting is naturally not implemented by the decorator, it is rather resolved by the decorated object (by calling decoratedPosting.postTrans()
). If I overlook the logic for a limit calculation and an over-limit transaction creating (which is our internal business), this is the all logic that was necessary to add. Whether it is easier to implement and test this class or a complexly branched method with hundreds of lines, you can evaluate by yourself.
A calling of our logic can by ensured by a simple change. Assume we have the following code in the TrvExpTablePost class:
TrvExpTransPost transPost = new TrvExpTransPost(); transPost.setExpTablePost(this); transPost.setLedgerJournalTable(ledgerJournalTable); transPost.postTrans(trvExpTransPost);
Let’s change a single line – the instance creation:
TrvExpTransPostProvider transPost = new TrvExpPostMySplitDecorator(new TrvExpTransPost()); transPost.setExpTablePost(this); transPost.setLedgerJournalTable(ledgerJournalTable); transPost.postTrans(trvExpTransPost);
Instead of a messed method with lots of duplicate code, we got a code logically divided to classes and methods. When somebody will be adding the mentioned additional splitting, he will have to only implement another decorator and place it before or after my decorator (nice thing is that the order is not important now). He doesn’t have to know anything about how transactions to post are selected, how journals are created etc., he’ll simply program one class encapsulating the requested logic. And if the original implementation was at least a bit reasonable, everything would be even much simpler.
PS: I concealed one thing above (due to simplicity). When a Cash Advance Return is being post, there is one extra step (not performed for other postings) – a value in the TrvCashAdvance table is changed. I implemented it as a decorator too – with only eight lines of code.