When we read the name of the pattern Decorator would imagine that silly name, meaningless. Good is not as meaningless as well.
The Decorator works exactly as the name describes.
Definition:
Decorator is a design pattern software that allows you to add a behavior to an existing object at runtime, or dynamically adds additional responsibilities to an object.
This pattern adds responsibilities dynamically to a class, generating more flexible alternative for certain classes use subclasses through inheritance or composition.
Using Decorator, we have more momentum in the inheritance, we can use inheritance without the problem of transforming our class’s into God class’s.
To help us understand the pattern, let’s create a scenario and a code example.
Scenario
Imagine we are developing a banking system where an account, you can transfer funds to accounts or savings accounts.
We have a problem to solve:
When we make the transfer money, we have an account and savings account. Following the pattern of Object Orientation, we must respect the division of responsibility.
So the account should be a class and savings account should be another class.
Our problem is to credit the account values and define how we will do it in a clean and easy to maintain.
The Decorator can help us do just that, he will add responsibility receiveFounds() in our class at the right time, including making the validation that determine what kind of account value will be credited. Here’s an example:
Account.cfc
<cfcomponent displayname="Account" extends="Decorator"> <cfscript> public Account function init() { this.numAccount = 0; this.numAtualFounds = 0; return this; } public String function transferFounds( Numeric numAccount , Numeric transferValue ) { var operationSuccess = false; operationSuccess = super.doFoundTransfer( this, arguments.numAccount , arguments.transferValue ); return operationSuccess; } public String function receiveTransferredFounds( Account numPayAccount , Numeric numAccount , Numeric transferValue ) { // implementation var result = "Account Transfer Successfull"; return result; } </cfscript> </cfcomponent>
SavingsAccount.cfc
<cfcomponent output="false" displayname="SavingsAccount"> <cfscript> public String function receiveTransferredFounds( Account numPayAccount , Numeric numAccount , Numeric transferValue ) { // implementations var result = "Savings Account Transfer Successfull"; return resultado; } </cfscript> </cfcomponent>
Decorator.cfc
<cfcomponent output="false" displayname="Decorator"> <cfscript> variables.DGS_VERIFY_SAVINGS_ACCOUNT = 500; package String function doFoundTransfer( Account numPayAccount , Numeric numAccount , Numeric transferValue ) { var account = ""; if( validateSavingsAccount( arguments.numAccount ) ) { account = CreateObject("component","SavingsAccount"); } else { account = CreateObject("component","Account"); } return account.receiveTransferredFounds( arguments.numPayAccount , arguments.numAccount , arguments.transferValue ); } private Boolean function validateSavingsAccount( Numeric numAccount ) { if( int( Right( arguments.numAccount , 3 ) == variables.DGS_VERIFY_SAVINGS_ACCOUNT ) ) { return true; } else { return false; } } </cfscript> </cfcomponent>
Implementation
<cfscript> variables.account = CreateObject("component","Account").init(); variables.account.numAccount = 26558454200; // transfer to account variables.resultTransfer = variables.account.transferFounds( 556558474154 , 6000.00 ); dump(variables.resultTransfer); // transfer to savings account variables.resultTransfer = variables.account.transferFounds( 556558474500 , 2365.50 ); dump(variables.resultTransfer); </cfscript>
Well as we saw above, we made two payments to two different accounts. No need to report what kind of account would be without having to instantiate anything more.
In the instance of our business, we transfer the responsibility and Decorator entered correctly in our method of transferring funds.
This pattern is very simple and very easy to use.
I hope you enjoyed, and good until the next code.