Go — Command Pattern
Prerequisite
Before reading this article, make sure you have a good understanding of Go Interface.
Introduction
Command Pattern falls under Behavioural Pattern, this pattern encapsulates a request as an object. By this way, while you have so many objects with its unique action, each object can be isolated to only focus on its own behaviour, and the invoker doesn’t have to know the implementation detail of the corresponding object that’s been requested.
Money first, then command
Money? yes, I like money and like most of you. And while I am thinking about money is all about command. Money commanding the world—of course after God and your mama—and for this example, I am glad to bring you to the money business.
Recently Joe von Borutzmann is a manager of a peer-to-peer lending company. The business is very simple, people can become a lender or a borrower.
Based on that requirement, after you imagine the money you will imagine poor people who need money. And another person has a lot of money that willing to lending her money to anyone else. But, let’s simplify the domain for our code to only record the loan data.
So we will create a Loan struct/domain as seen below:
I think the attributes and the functions are clear enough, so let’s move to the next move.
Every P2P lending activity should have a transaction order, so we can create a service that can perform lend and borrow money.
First, create Order interface, in Command Pattern this interface usually called command interface
Second, create borrow service that implements command interface
Third, create lend service that also implements command interface
Fourth, we need a cashier or teller to works as a mediator between lender and borrower. At this point, in Command Pattern this also known as invoker
See, the invoker doesn’t care what action needs to be performed there. Because, as in the real world, the bank teller will know if the lender will lend the money and borrower will borrow the money. So, teller only cares to perform the order.
Fifth, we will put in the main function to run this Command Pattern
As you can see, the teller only needs to serve `lendMoney` or `borrowMoney` object as request param. And the result can be seen as below:
Lending money 9000.00
Borrowing money 9000.00
Also, by this pattern, you can extend the ability of your code. For example, if there is a reconciliation for the loan that has been performed.
To add reconciliation, we need to add new function in loan domain and new reconciliation service
First, add reconcile function in the Loan domain
Second, create a new service, called reconcile service
Finally, the main function will be seen as below
Run that new code, the result will be seen as below:
Lending money 9000.00
Borrowing money 9000.00
Reconcile Loan Id A-1 with amout 9000.00
Conclusion
Based on the explanation above, we can get the code more readable and each service has a single responsibility. Also, the invoker doesn’t have to use if/else
pattern to execute the specific action.
Imagine if you have complex lend and borrow service in the real P2P lending system. By this Command Pattern, each of command for the corresponding feature can be separated into different file/service. It will help if there is a requirement to remove a particular feature, you can remove the corresponding file/service. Also, to add a new feature, add a new file for the new service. By this way, the other service that doesn’t have to be changed, will not get any code modification that will be causing hassle activities.
Extra Notes: Gopher is Go Language mascot (used as part of the image cover in this article), created by Renee French. Creative Commons Attribution 3.0 licensed.