I have code that violates the DRY
principle and I would like to consolidate 2 methods as much as I can, but the problem I am facing is that they have some differences, I would say they are about 75% the same, but the other 25% is different in certain areas. What kinds of design patterns or design approaches can I do to turn 2 methods into 1 or at least limit the code needed in each, so that they become more scalable and maintainable?
4
This is difficult to answer without looking at the code. However, it is clear that these methods are trying to do too much. They are almost certainly violating the SRP.
I would suggest that you begin by looking at where the methods are different and why. Perhaps you could use method injection to inject different code into the method, based on who or what is calling it.
Fundamentally, when it comes to refactoring code like this you should be trying to figure out why the code is the same and why it is different. Once you understand these two things, you can then factor these methods so that they are no longer trying to do too much.
6
Too difficult to assess without having a code segment to analyse.
Method consolidation should definitely be applied here, you’re just going to need to keep a few principles in mind. Have a read through this article on Jeff Atwood’s blog:
Curly’s Law: Do One Thing
Pay attention to the three core principles of modern software development, namely:
- Don’t Repeat Yourself
- Once and Only Once, and
- Single Point of Truth
Although I personally wouldn’t recommend the following, I’m going to show you an example for simplicity sake if you simply wish to wrap things up:
function my_method(variable){
/*
* 75% of method here
*/
if (variable == 0){
/* variation one here */
}
else{
/* variation two here */
}
return value;
}
1
One common way to refactor code like this is through inheritance, using abstract or virtual methods for the behavior that may vary.
Let’s say you have a method to pay employees, and another one to pay the CEO:
void PayNormalEmployee()
{
// do stuff
// do more stuff
// give meager bonus
// do final stuff
}
void PayCeo()
{
// do stuff
// do more stuff
// give huge bonus
// do final stuff
}
Let’s assume that you have to do things in the order above; you can’t just reorder to set the bonus part as the last step.
The way to refactor this is through inheritance. You put the common behavior in a base class, and put the distinct behavior in distinct subclasses. Your common line (or set of lines) should call out to a separate method. For instance:
abstract class EmployeeBase
{
public void Pay()
{
// do stuff
// do more stuff
PayBonus();
// do final stuff
}
protected abstract void PayBonus();
}
class NormalEmployee : EmployeeBase
{
override void PayBonus()
{
// pay meager bonus
}
}
class Ceo : EmployeeBase
{
override void PayBonus()
{
// pay huge bonus
}
}
Whether your employee is a NormalEmployee or a CEO, he/she has access to the Pay method, but the implementation in the derived class will be used.
If there’s a “default” implementation, you can make this simpler:
class Employee
{
public void Pay()
{
// do stuff
// do more stuff
PayBonus();
// do final stuff
}
protected virtual void PayBonus()
{
// pay meager bonus
}
}
class Ceo : Employee
{
override void PayBonus()
{
// pay huge bonus
}
}
Again, the CEO has access to the Pay method, but will use his/her special PayBonus implementation; but everything will still happen in the proper order.