Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

How I Used the Decorator Pattern to Solve my Tech Issue

DZone 's Guide to

How I Used the Decorator Pattern to Solve my Tech Issue

Need help finding a monolithic approach for building your codebase? Click here to learn how we used a decorator pattern to solve this problem.

· Java Zone ·
Free Resource

Our code base followed a hybrid monolithic approach where we had a huge codebase with tens of thousands of classes. On a complete build of the code base, we had five major JARs builds with dependencies pulled.

Now, I was working on the moduleAccountsManager. We had one another module, UpgradeManager, which allowed us to create a self-upgrade of all the other modules, including our AccountsManager, whereby it installs the latest RPM when its given a new RPM path (it does dozens of other things that are out of our scope).

So, we had the class UpgradeServiceImpl which can be seen as follows in the UpgradeManager:

class UpgradeServiceImpl implements UpgradeService {

// So many things here 

public UpgradeStatus upgrade(Spec spec){

//some more things here 

initiateUpgrade();
}

}


In my module, AccountsManager rest controller, it was used as below:

@RestController("/accounts")
class AccountsManagerUpgrade {

@Autowired UpgradeService upgradeService;

//So many things here 


@PostMapping("/upgrade")
public void upgrade(Spec spec) { //spec contains path of new RPM , version etc

//somethings here includin validation etc

return upgradeService.upgrade();

}
}


Problem Statement

We had to introduce more logic in the UpgradeService of the UpgradeManager where more conditions had to be met before saying it's upgraded completely .

We tried this a couple of ways. First, we introduced an OptionalBean in UpgradeService and only our module creates and loads the bean. This for sure was working, but as you know, it's not always good to touch some one else' code.

So, we came up with a decorated design where we use the original UpgradeService without any change, but we decorated it as per our desire. Let's take a closer look.


Step 1

We created an exact replica (only the methods) as that of the UpgradeService in our module .

class AccountsManagerUpgradeStatusService {

 public UpgradeStatus upgrade(Spec spec) {

 }
 }


Step 2

Next, we add the original UpgradeService as a dependency in the new class and call the original upgrade method from the UpgradeService:

class AccountsManagerUpgradeStatusService {

 @Autowired UpgradeService upgradeService;

 public UpgradeStatus upgrade(Spec spec) {

 upgradeService.upgrade(spec);

 }
 }


Now, we can safely switch the original UpgradeService from the RestController to the new AccountsManagerUpgradeStatusService as shown below:

@RestController("/accounts")
class AccountsManagerUpgrade {

//@Autowired UpgradeService upgradeService; - removed this

@Autowired AccountsManagerUpgradeStatusService upgradeService; //added this

//So many things here 


@PostMapping("/upgrade")
public void upgrade(Spec spec) { //spec contains path of new RPM , version etc

//somethings here includin validation etc

return upgradeService.upgrade();

}
}


Step 3

Now, in the new AccountsManagerUpgradeStatusService, we can add it as per our requirement:

class AccountsManagerUpgradeStatusService {

 @Autowired UpgradeService upgradeService;

 public UpgradeStatus upgrade(Spec spec) {

 //we can do many things her now
 UpgradeStatus status = upgradeService.upgrade(spec);

 //do some more validation/RPM upgrade check , here and return the status

 return status;

 }
 }


As you can see, we can now safely add more validations or checks after we get the status and our upgrade is complete by not touching the original Upgrade code.

Happy coding!

Topics:
decorator design pattern ,design pattern ,spring boot 2.0 ,java ,tutorial

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}