-1

I have a class that is 99% identical to its counter part. Sample code goes below:

public abstract class BaseClass
{
    void Method1() { }
    void Method2() { }
    void Method3() { }
    public void MainMethod(List<Object1> listObject)
    {
        Method1();
        Method2();
        Method3();
        Method4();
    }

    abstract internal void Method4();

}

public sealed class DerivedClass : BaseClass
{
    internal override void Method4()
    {
        throw new NotImplementedException();
    }
}

public class BaseClass2
{
    void Method1() { }
    void Method2() { }
    void Method3() { }
    public void MainMethod2(List<Object2> listObject)
    {
        Method1();
        Method2();
        Method3();
    }

}

As You can see that BaseClass and BaseClass2 are almost identical with Method1 ... Method3. Is there a better alternative that can be used to minimize duplication of code.


I initially started this polymorphism as an encouraging stuff, I have over 11 derived classes on BaseClass, and because of the second implementation of MainMethod2, I am stuck with duplication of code.

I just cannot think of any clever way to get out of it.


Update: So this question is potentially containing two parts:

1. How to avoid duplication of code? I solved this by using Composition successfully as suggested by wonderful answers below.

2. How to avoid leaky abstractions? With this I am still struggling...

  • 2
    Is there some relationship between BaseClass and BaseClass2? If there is, you should absolutely try to express that in your code. If there isn't, there's just an unfortunate overlap in naming, but that tends to only happen with toy examples in my experience. In real code, when the names and structure are highly coinciding, there either should be a formally-expressed relationship or you should pick names to be more descriptive (calling internal methods FooBar1 and FooBar2 all the time is not good practice!) – Donal Fellows Nov 21 '13 at 17:51
  • In real world BaseClass and BaseClass2 are Agent Classes that call to services exposed outside my application. Both of these classes call to the same service hence they have common Channel and password and all the stuff. – shankbond Nov 21 '13 at 17:54
  • 2
    I probably overlooking the obvious, but what is your problem exactly? If method1-3 are identical implementation-wise, you could just inherit base from base2 (but you probably know that already) and just add method4(). If the methods have the same name but different implementations, then it's not really a duplicate: either make them virtual or think of a different name, depending on the intention. Or you may consider the strategy pattern. Or composition. – JensG Nov 21 '13 at 18:06
  • 1
    @JensG I have updated my question. I am avoiding or cannot think of better alternative of inheritance between BaseClass and BaseClass2. The Point 2 of answer posted below seems perfect to use composition for getting rid of Method1 ... Method3. – shankbond Nov 22 '13 at 1:30
1

I see two options.

  1. Change BaseClass to contain an instance of BaseClass2. Change BaseClass.MainMethod to invoke BaseClass2.MainMethod (instead of its own implementation of Methods 1-3).

  2. Refactor Method1, Method2, and Method3 into a new class. Change BaseClass and BaseClass2 to use the new class (instead of their own implementation of Methods 1-3).

  • point 2 seems perfect, for point 1 MainMethod of BaseClass and BaseClass2 have different method signatures which I forgot to mention, I am updating question. – shankbond Nov 22 '13 at 1:18
  • for point 1 I don't understand it. an example would be helpful – shankbond Nov 22 '13 at 1:22
1

Simplest thing is to get rid of BaseClass2. It's subclasses should just extend BaseClass and override Method4 with a method that does nothing.

Failing that, have BaseClass2 override BaseClass. All it would need is MainMethod2.

You could go one step further and get rid of MainMethod2 and replace it with an override for MainMethod that only calls Methods 1, 2 & 3.

  • 1
    don't You think that "override Method4 with a method that does nothing." produces leaky abstraction? Also I cannot do an "override for MainMethod " please see my updated question (both of the method signatures are different). – shankbond Nov 22 '13 at 1:25
  • @shankbond: No I don't. Empty methods can be as useful as the digit zero. You are only telling it what to do in a particular case. And it's worth a lot to have everything be a BaseClass. ("Do nothing"--for now.) Next, you could make more use of generics: public abstract BaseClass<T> and public void MainMethod2( List<T> listObject. Or add a MainMethod2 to BaseClass, though this too might produce a "leaky abstraction". My view here is again: it's worth a lot to have everything be a BaseClass. – RalphChapin Nov 22 '13 at 14:24
0

It sounds like what you want is the Strategy Pattern. Your methods are your "Strategy" following an interface. I'm going to make your methods return float and take two float as arguments to help illustrate the strategy pattern:

interface MathsStrategy {
    float execute(float a, float b);
}

and you have some classes that implement this interface:

// Method1
class Add implements MathsStrategy {
    public float execute(float a, float b) {
        return a + b;  
    }
}

// Method2 
class Subtract implements MathsStrategy {
    public float execute(float a, float b) {
        return a - b;  
    }
}

// Method3
class Multiply implements MathsStrategy {
    public float execute(float a, float b) {
        return a * b;  
    }
}

and you could wrap Method1, Method2, and Method3 together as you use them in a group:

// Composite of Method1, Method2 and Method3
class CompositeOf123 implements MathsStrategy {
    public float execute(float a, float b) {
        return new Add().execute(a, b) + new Subtract().execute(a, b) + new Multiply().execute(a, b);  
    }
}

Okay, contrived but hopefully you get the point.

Then we have the methods that vary:

// First example of Method4
class Divide implements MathsStrategy {
    public float execute(float a, float b) {
        return a / b;  
    }
}

// Second example of Method4
class Exponentiation implements MathsStrategy {
    public float execute(float a, float b) {
        return a ^ b;  
    }
}

Summing up, we have a few methods that we use frequently and want to use in composite and some different implementations that we want to use sometimes so we create different strategies for these.

Now, if we pass these to the class as part of the constructor then we don't really even need the inheritance. It is the behaviour of the method that needs to change, not the class itself. This way we don't need to alter the class to implement a different strategy, we just pass the strategy to the class' constructor when we create an instance of the class.

So your class becomes:

public class MyClass
{
    private MathsStrategy strategy;

    public MyClass(MathsStrategy maths) {
        strategy = maths;
    }

    public float MainMethod(float a, float b) {
        return strategy.execute(a, b);
    }
}

Now you just have to create instances of MyClass that will use the different strategies as required:

float a = 15.0F;
float b = 25.0F;
float result;

MyClass addition = new MyClass(new Add());  // This instance does addition
result = addition.MainMethod(a, b);

MyClass composite = new MyClass(new CompositeOf123()); // This instance does addition, subtraction and multiplication
result = composite.MainMethod(a, b);

MyClass exp = new MyClass(new Exponentiation());  // This instance does one version of Method4
result = exp.MainMethod(a, b);

These instances of the classes will execute the appropriate strategy (in this case a simple maths equation) when you call the MainMethod method. This gives a much cleaner class structure and separation of concerns.

0

You could also pass delegates to your function. Your method1,...,method4 seem to have the same signature. Build a higher order function (your new main method) which takes multiple delegates as parameters and executes them. Sorry for missing example, I'm on the phone. I'll edit it tomorrow though

---Example---

public delegate void ADelegate();

public void someOtherFunction() {

    var methodsToCall = method1 + method2 + method3 + method4;
    newMain(methodsToCall);

    var methodsToCall -= method4;
    newMain(methodsToCall);
}

public void newMain(ADelegate aDelegate){
    aDelegate();
}    

public void method1() {...};
public void method2() {...};
public void method3() {...};
public void method4() {...};

It's untested, but I think you can get the idea

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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