Изменение сигнатур абстрактных методов в унаследованных классах - PullRequest
11 голосов
/ 08 апреля 2011

Представьте, что у меня есть класс с именем Engine в качестве абстрактного базового класса. У меня также есть классы ElectrictEngine и FuelEngine, которые происходят от него.

Я хочу создать метод для заправки двигателя. Должен ли я сделать это как абстрактный метод на уровне базового класса и назвать его в общем стиле, например, fillUpEnergy?

Проблема в том, что, если у меня есть электрический двигатель, число параметров, которые принимает метод, отличается от количества параметров, которые необходимо передать для топливного двигателя. Итак, подпись метода другая.

Кроме того, есть ли какой-нибудь разумный способ использовать универсальный метод для обоих движков, но обернуть его более конкретным именем? Например: для топливного двигателя «заправка», а для электрического двигателя «заряд батареи»? И в то же время скрыть универсальный метод от пользователя?

Ответы [ 5 ]

6 голосов
/ 08 апреля 2011

В этой ситуации я бы определил универсальную реализацию вашего абстрактного класса так, чтобы вы получили что-то вроде этого:

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

Тогда ваши реализации выглядят так:

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

В качестве альтернативы , вы можете определить интерфейс и передать конкретную реализацию вашим методам:

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

Тогда ваши реализации будут выглядеть так:

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;
     }
}
2 голосов
/ 08 апреля 2011

У вас может быть метод для заправки, который занимает интерфейс?

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

Какие параметры принимают ваши два типа заправки?

2 голосов
/ 08 апреля 2011

Подумайте больше о том, как вы будете использовать эти классы.Если ваш клиент не знает, с каким двигателем он имеет дело - у него есть «Двигатель», тогда вы должны найти «заправочную» подпись, которую может использовать boht.с другой стороны, если у вас должны быть разные аргументы для каждого вида дозаправки, то вы не можете ничего сделать в базовом классе, и вместо этого вам нужно, чтобы ваш клиент знал, какой это двигатель, и передавал нужные аргументы.

0 голосов
/ 09 апреля 2011

Абстрактный класс действительно не подходит, потому что Refuel не является функцией (методом), которая принимает тип суммы в качестве параметра.

Как насчет чего-то подобного?

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);
    }
}
0 голосов
/ 08 апреля 2011

Я бы разделил двигатель и заправляемые / перезаряжаемые детали. Или вы должны обобщить все, что касается двигателя. Например, вы можете создать другой абстрактный тип (или интерфейс) Charge и передать его в метод recharge (который определен в родительском абстрактном классе Engine). Дайте мне знать, если вам нужен код.

...