11

Imagine I have a class called Engine as an abstract base class. I also have ElectrictEngine and FuelEngine classes which derive from it.

I want to create a method for refueling the engine. Should I do it as an abstract method on the base class level and name it in a generic fasion, such as fillUpEnergy?

The problem is that if I have an electric engine, the number of parameters which the method takes is different from the number of parameters which need to be passed for a Fuel Engine. So, the method's signature is different.

In addition, is there any smart way to use the generic method for both engines but to wrap it in a more specific name? For example: for a fuel Engine, "refuel", and for an electric engine, "chargeBattery"? And at the same time hide the generic method from the user?

Esoteric Screen Name
  • 6,082
  • 4
  • 29
  • 38
Mulder
  • 2,817
  • 3
  • 17
  • 7

5 Answers5

6

In this situation, I would define a generic implementation of your abstract class, such that you get something like this:

public abstract class EngineBase<T>
{
     public abstract void Refuel(T parameters);
}

Then your implementations look like this:

public class ElectricEngine : EngineBase<ElectricParameters>
{
     public override void Refuel(ElectricParameters parameters) { }
}

Alternatively, you can define an interface, and pass a specific implementation to your methods:

public abstract class EngineBase
{
     public abstract void Refuel(IRefuelParameters parameters);
}

Then your implementations look like this:

public class ElectricEngine : EngineBase
{
     public override void Refuel(IRefuelParameters parameters)
     {
          if(!(parameters is ElectricParameters))
              throw ApplicationException("Not the right params!");

          ElectricParameters rightParams = parameters as ElectricParameters;
     }
}
user541686
  • 205,094
  • 128
  • 528
  • 886
Tejs
  • 40,736
  • 10
  • 68
  • 86
  • While the first solution directly solves the issue with the parameters, it makes the base class useless. The interface solution is much better. – siride Apr 08 '11 at 15:37
2

Think more about how you will use these classes. If your client won't know what kind of engine they're dealing with - they have an 'Engine' then you have to figureo out a 'refuel' signature that boht can use. if on the other hand you HAVE to have different args for each kind of refueling, then you can't do anything in the base class and have to instead have your client know what kind of engine it is and pass the right args.

n8wrl
  • 19,439
  • 4
  • 63
  • 103
2

You could have a method to refuel that takes an interface?

eg
public void Refuel(IFuel fuel)
{
//do refueling logic
}

What parameters do your two types of refueling take?

WraithNath
  • 17,658
  • 10
  • 55
  • 82
  • This is clever. It will be very interesting to see how IFuel can be used generically. – n8wrl Apr 08 '11 at 15:17
  • depending on what parameters the other two methods would take it may be possible. The IFuel interface could have a method that returns a decimal for the amount of fuel increate for example – WraithNath Apr 08 '11 at 15:19
  • Yeah. I was thinking if 'fueling' involved not spilling any or not doing it in the rain it's still engine-type-ish. – n8wrl Apr 08 '11 at 16:00
0

I would separate the engine and the refuel-able/rechargeable parts. Or you have to generalize all the things concerning the engine. For example, you can make another abstract type (or interface) Charge, and pass this to recharge method (which is defined in the parent abstract Engine class). Let me know, if you need some code.

khachik
  • 28,112
  • 9
  • 59
  • 94
-1

An abstract class really isn't appropriate because Refuel is not a function (method) that takes a sum type as a parameter.

How about something like this?

interface IEngine
{
    void Refuel(FuelingStation station);        
}

class FuelingStation
{
    double Gas;
    double Air;
    double Charge;


    private double GetFuel(ref double fuel, double requested)
    {
        var temp = Math.Max (0, fuel - requested);

        fuel -= temp;

        return temp;
    }


    public double GetGas(double requestedAmount)
    {
        return GetFuel (ref Gas, requestedAmount);

    }

    public double GetAir(double requestedAmount)
    {
        return GetFuel (ref Air, requestedAmount);
    }

    public double GetCharge(double requestedAmount)
    {
        return GetFuel (ref Charge, requestedAmount);
    }
}


class GasEngine : IEngine
{

    double Tank;
    double Capacity;


    public void Refuel(FuelingStation station)
    {
        Tank = station.GetGas (Capacity - Tank);
    }
}


class Electric : IEngine
{

    double Charge;
    double ChargeCapacity;

    double Tank;
    double TankCapacity;



    public void Refuel(FuelingStation station)
    {
        Tank = station.GetGas (TankCapacity - Tank);
        Charge = station.GetCharge (ChargeCapacity - Charge);
    }
}
Rodrick Chapman
  • 5,437
  • 2
  • 31
  • 32