0

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
  • 5
    Post them as examples please. Feb 27, 2015 at 6:02
  • 3
    Consider using the Template pattern
    – sakisk
    Feb 27, 2015 at 13:05
  • 1
    So 3 of the 4 lines are the same? Feb 28, 2015 at 0:23
  • I think this is a valid question. There are many patterns of code reuse; a product of code deduplication. Going over them doesn't require intimate knowledge of the code as you can enumerate and explain the relative strengths and weaknesses of each. For example inline conditionals, parameterization, inheritance, function/object delegation, mixins, function wrapping (or more broadly Adaptors), functional composition, pipes and filters, etc. Albeit this may be too broad and having the language at least would allow a reduction in the number of patterns available.
    – snakehiss
    May 4, 2015 at 4:03

3 Answers 3

6

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
  • 2
    What is method injection? Do you mean like using a delegate?
    – xaisoft
    Feb 27, 2015 at 5:58
  • Yes, using a delegate to inject the different code into the method.
    – Stephen
    Feb 27, 2015 at 6:12
  • or you could use @moose's suggestion and keep your code maintainable and easy to read and understand!
    – gbjbaanb
    Feb 27, 2015 at 15:21
  • 2
    @gbjbaanb The delegate solution is more maintainable than hard-coding a new branch into the method for every new minor variation you discover. Write the skeleton once and be done with it.
    – Doval
    Feb 27, 2015 at 15:30
  • That it violates SRP is a rather large assumption. Just because code 75% similar between 2 methods says nothing about responsibility, singular or multiple. It could be the exception handling code is duplicated except for a variant behavior such as some additional cleanup.
    – snakehiss
    May 4, 2015 at 3:47
3

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:

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
  • The if/else thingy is quite ugly. You should have two methods for the specific parts (the if/else blocks) and another method for the common part - that would be much cleaner IMO...
    – assylias
    Feb 27, 2015 at 22:51
2

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.

Not the answer you're looking for? Browse other questions tagged or ask your own question.