zzfima
zzfima

Reputation: 1565

How to extract abstraction?

My question is trivial, but i can not find proper solution.

Code (just for example):

public class ToRefact
{
    public int Func1(int i)
    {
        int a = i;
        a++;
        a++;
        a++;

        int b = FuncX2(a); //b = a * 2;

        b++;
        b++;
        b++;
        return a + b;
    }

    public int Func2(int i)
    {
        int a = i;
        a++;
        a++;
        a++;

        int b = FuncX3(a); // b = a * 3;

        b++;
        b++;
        b++;
        return a + b;
    }

    private int FuncX2(int b)
    {
        return b * 2;
    }

    private int FuncX3(int b)
    {
        return b * 3;
    }
}

We can see, func1 and func2 has same body, except of middle of code: differences is FuncX2 and FuncX3. But, i can not do base abstract class because this code in the middle! How can i do common abstraction? Please, do not change operations (3 times a++, 3 times b++) and do not change sequence

Thanks

Upvotes: 0

Views: 129

Answers (5)

sbgoran
sbgoran

Reputation: 3541

You could use template method (or even strategy pattern depending on real scenario) but in this simple case I would do something like this:

public class ToRefact
{
    public int Func1(int i)
    {
        int a = FuncAdd3(i);

        int b = FuncX2(a); //b = a * 2;

        b = FuncAdd3(b);
        return a + b; // Or more compact FuncAdd3(i) + FuncAdd3(FuncX2(FuncAdd3(i)))
    }

    public int Func2(int i)
    {
        int a = FuncAdd3(i);

        int b = FuncX3(a); //b = a * 2;

        b = FuncAdd3(b);
        return a + b; // Or more compact FuncAdd3(i) + FuncAdd3(FuncX3(FuncAdd3(i)))
    }

    private int FuncAdd3(int b)
    {
        return b + 2;
    }

    private int FuncX2(int b)
    {
        return b * 2;
    }

    private int FuncX3(int b)
    {
        return b * 3;
    }
}

Upvotes: 1

L-Four
L-Four

Reputation: 13541

Alternatively you could create a more modular and testable approach.

Create ICalculator interface like:

 public interface ICalculator
 {
      int Calculate(int a);
 }

And two concrete implementations

public class CalculatorX : ICalculator
{
      public int Calculate(int a)
      {
          return a * 2;
      }
}

public class CalculatorY : ICalculator
{
      public int Calculate(int a)
      {
          return a * 3;
      }
}

Then you would accept this as a parameter:

public int Func1(ICalculator calculator)
{
    int a = i;
    a++;
    a++;
    a++;

    int b = calculator(a); 

    b++;
    b++;
    b++;
    return a + b;
}

And call it like:

var calculatorX = new CalculatorX();
var result = Func1(calculatorX );

This makes it easy to replace implementations, mock them out, even inject them using your favorite IoC container. You also explicitly specify the contract of your method, so that if you ever have to add a new implementation, you know what to implement thanks to the interface.

Upvotes: 1

Lieven Keersmaekers
Lieven Keersmaekers

Reputation: 58491

You can create a base class and apply the template method design pattern.

Example

note that I've used Delphi as that's easiest for me to write from memory but the intent is the same in every language that has virtual and abstract methods

  TCustomRefact = class(TObject)
  protected
    function Calculate;
    function Multiply(const Value: Integer); virtual; abstract;
  end;

  TRefact1 = class(TCustomRefact )
  protected
    function Multiply(const Value: Integer); override;
  end;

  TRefact2 = class(TCustomRefact )
  protected
    function Multiply(const Value: Integer); override;
  end;

Upvotes: 0

Krimson
Krimson

Reputation: 7674

public class ToRefact{
    public int Func1(int i){
        int a = i;
        a = addThree(a);

        int b = FuncX2(a); //b = a * 2;

        b = addThree(b);
        return a + b;
    }

    public int Func2(int i){
        int a = i;
        a = addThree(a);

        int b = FuncX3(a); // b = a * 3;

        b = addThree(b);
        return a + b;
    }

    private int FuncX2(int b){
        return b * 2;
    }

    private int FuncX3(int b){
        return b * 3;
    }

    private int addThree(int x){
        x++;
        x++;
        x++;
        return x;
    }
}

Upvotes: 0

Anton Gogolev
Anton Gogolev

Reputation: 115859

Assuming your language of choice can pass around "pointers" to functions:

public class ToRefact
{
    private int Func(int i, Func<int, int> f)
    {
        int a = i;
        a++;
        a++;
        a++;

        int b = f(a); //b = a * 2;

        b++;
        b++;
        b++;
        return a + b;    
    }

    public int Func1(int i)
    {
        return Func(i, FuncX2);
    }

    public int Func2(int i)
    {
        return Func(i, FuncX3);
    }

    private int FuncX2(int b)
    {
        return b * 2;
    }

    private int FuncX3(int b)
    {
        return b * 3;
    }
}

Upvotes: 2

Related Questions