Question

Quelle est la bonne conception dans ce cas simple:

Disons que j'ai une classe de base voiture avec une méthode où FillTank(Fuel fuel) carburant est également une classe de base qui ont plusieurs classes de feuilles, diesel, etc éthanol.

Sur ma feuille classe voiture DieselCar.FillTank(Fuel fuel) seulement un certain type de carburant est autorisé (pas de surprise là-bas :)). Maintenant, voici ma préoccupation, selon mon interface chaque voiture peut être tanké avec tout carburant, mais qui semble mal à moi, dans chaque mise en œuvre de FillTank() vérifier le carburant d'entrée pour le type correct et sinon jeter une erreur ou quelque chose.

Comment puis-je REFONTE ce cas à un plus précis, est-il possible? Comment concevoir une méthode de base qui prend une classe de base pour l'entrée sans obtenir ces résultats « étranges »?

Était-ce utile?

La solution

S'il y a une limite difficile entre les types de voitures et les types de carburant, alors FillTank() n'a pas d'affaire dans la classe de base Car, car sachant que vous avez une voiture ne vous dit pas ce type de carburant. Donc, pour ce pour assurer la correction à temps de compilation, FillTank() doivent être définis dans les sous-classes, et ne devrait pas prendre la sous-classe Fuel qui fonctionne.

Mais si vous avez un code commun que vous ne voulez pas répéter entre les sous-classes? Ensuite, vous écrivez un protégé méthode FillingTank() pour la classe de base que les appels de fonction de la sous-classe. Même chose pour Fuel.

Mais si vous avez une voiture magique qui fonctionne sur plusieurs carburants, par exemple le diesel ou le gaz? Ensuite, cette voiture devient une sous-classe des deux DieselCar et GasCar et vous devez vous assurer que Car est déclarée comme une superclasse virtuelle de sorte que vous n'avez pas deux instances de Car dans un objet DualFuelCar. Remplissage du réservoir devrait fonctionner avec peu ou pas de modification. Par défaut, vous aurez à la fois DualFuelCar.FillTank(GasFuel) et DualFuelCar.FillTank(DieselFuel), vous donnant une fonction par type de surcharge

Mais si vous ne voulez pas la sous-classe d'avoir une fonction de FillTank()? Ensuite, vous devez passer à temps d'exécution vérifier et faire ce que vous pensiez que vous aviez à: faire le Fuel.type de contrôle de sous-classe et soit lancer une exception ou retourner un code d'erreur (préférez celui-ci) s'il y a un décalage . En C ++, RTTI et dynamic_cast<> sont ce que je recommande. En Python, isinstance().

Autres conseils

Utilisez une classe de base générique (si votre langue prend en charge (le ci-dessous est C #)):

public abstract class Car<TFuel>  where TFuel : Fuel
{
    public abstract void FillTank(TFuel fuel);
}

Fondamentalement, il applique une classe qui hérite de voiture pour spécifier le type de carburant utilisé. De plus, la classe Car impose une restriction TFuel doit être un sous-type de la classe abstraite Fuel.

Disons que nous avons une Diesel de classe qui est simple:

public class Diesel : Fuel
{
    ...
}

Et une voiture qui ne fonctionne que sur le diesel:

public DieselCar : Car<Diesel>
{
     public override void FillTank(Diesel fuel)
     {
          //perform diesel fuel logic here.
     }
}

La programmation orientée objet seul ne peut pas bien gérer ce problème. Qu'est-ce que vous avez besoin est (solution C ++ montré ici) de programmation générique:

template <class FuelType>
class Car
{
public:
  void FillTank(FuelType fuel);
};

Votre voiture diesel est alors juste une voiture spécifique, Car<Diesel>.

envoi à double peut être utilisé pour cela: accepter un peu de carburant avant avant le remplissage. Rappelez-vous que dans le langage qui ne supportent pas directement, vous introduisez les dépendances

On dirait que vous voulez juste de limiter le type de carburant qui va dans votre voiture diesel. Quelque chose comme:

public class Fuel
{
    public Fuel()
    {
    }
}

public class Diesel: Fuel
{
}

public class Car<T> where T: Fuel
{
    public Car()
    {
    }

    public void FillTank(T fuel)
    {
    }
}

public class DieselCar: Car<Diesel>
{
}

ferait l'affaire par exemple.

var car = new DieselCar();
car.FillTank(/* would expect Diesel fuel only */);

Essentiellement ce que vous faites ici permet à un Car d'avoir des types de combustibles spécifiques. Il vous permet également de créer une voiture qui soutiendrait tout type de Fuel (la chance serait une bonne chose!). Cependant, dans votre cas, le DieselCar, vous simplement dériver une classe de voiture et la limiter à l'utilisation que du carburant Diesel.

utiliser l'opérateur is pour vérifier contre les classes acceptées, et vous pouvez lancer une exception dans le constructeur

Je pense que la méthode acceptée serait d'avoir une méthode ValidFuel(Fuel f) dans votre classe de base qui jette une sorte de NotImplementedException (différentes langues ont des termes différents) si les voitures « feuilles » ne remplacent pas.

FillTank pourrait être alors entièrement dans la classe de base et appelez ValidFuel pour voir si elle est valide.

public class BaseCar {
    public bool ValidFuel(Fuel f) {
        throw new Exception("IMPLEMENT THIS FUNCTION!!!");
    }

    public void FillTank(Fuel fuel) {
        if (!this.ValidFuel(fuel))
             throw new Exception("Fuel type is not valid for this car.");
        // do what you'd do to fill the car
    }
}

public class DieselCar:BaseCar {
    public bool ValidFuel(Fuel f) {
        return f is DeiselFuel
    }
}

Dans un système comme CLOS, vous pouvez faire quelque chose comme ceci:

(defclass vehicle () ())
(defclass fuel () ())
(defgeneric fill-tank (vehicle fuel))
(defmethod fill-tank ((v vehicle) (f fuel)) (format nil "Dude, you can't put that kind of fuel in this car"))

(defclass diesel-truck (vehicle) ())
(defclass normal-truck (vehicle) ())
(defclass diesel (fuel) ())
(defmethod fill-tank ((v diesel-truck) (f diesel)) (format nil "Glug glug"))

vous donnant ce comportement:

CL> (fill-tank (make-instance 'normal-truck) (make-instance 'diesel))
"Dude, you can't put that kind of fuel in this car"
CL> (fill-tank (make-instance 'diesel-truck) (make-instance 'diesel))
"Glug glug"

Ce qui, vraiment, est la version Common Lisp d'envoi double, comme mentionné par stefaanv .

vous pouvez étendre votre interface de voiture originale

interface Car {
    drive();
}

interface DieselCar extends Car {
    fillTank(Diesel fuel);
}

interface SolarCar extends Car {
    chargeBattery(Sun fuel);
}

}

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top