Comment puis-je effectuer l'injection de dépendance sans casser l'encapsulation?
À l'aide d'une Injection de Dépendance exemple de Wikipedia:
public Car {
public float getSpeed();
}
Remarque: d'Autres méthodes et propriétés (par exemple PushBrake(), PushGas(), SetWheelPosition() ) omis par la clarté
Cela fonctionne bien; vous ne savez pas comment mon objet implémente getSpeed
- il est "encapsulé".
En réalité, mon objet implémente getSpeed
comme:
public Car {
private m_speed;
public float getSpeed( return m_speed; );
}
Et tout est bien. Quelqu'un construit mon Car
objet, brasse les pédales, la corne, le volant et la voiture répond.
Maintenant, disons que j'ai modifier une mise en œuvre interne de détail de ma voiture:
public Car {
private Engine m_engine;
private float m_currentGearRatio;
public float getSpeed( return m_engine.getRpm*m_currentGearRatio; );
}
Tout est bien. L' Car
est de bonnes OO-principes, en masquant les détails de la façon dont quelque chose est fait. Cela libère de l'appelant pour résoudre ses problèmes, plutôt que d'essayer de comprendre comment une voiture qui fonctionne. Il me donne aussi la liberté de changer de mon oeuvre, comme je l'entends.
Mais l'injection de dépendance serait me forcer à exposer ma classe à un Engine
objet que je n'ai pas de créer ou d'initialisation. Même pire, c'est que j'ai maintenant exposés que mes Car
même a un moteur:
public Car {
public constructor(Engine engine);
public float getSpeed();
}
Et maintenant, la parole extérieure est conscient du fait que j'utilise un Engine
. Je n'ai pas toujours l'utilisation d'un moteur, je peux avoir envie de ne pas utiliser un Engine
dans le futur, mais je ne peux plus modifier mes internes de mise en œuvre:
public Car {
private Gps m_gps;
public float getSpeed( return m_gps.CurrentVelocity.Speed; )
}
sans rupture de l'appelant:
public Car {
public constructor(Gps gps);
public float getSpeed();
}
Mais l'injection de dépendance ouvre un ensemble de vers: par l'ouverture de l'ensemble de la boîte de pandore. L'Injection de dépendance exige que tous mes objets privés détails de mise en œuvre de l'exposition. La consommation de mon Car
classe a maintenant de comprendre, et de les traiter, tous précédemment cachés interne subtilités de ma classe:
public Car {
public constructor(
Gps gps,
Engine engine,
Transmission transmission,
Tire frontLeftTire, Tire frontRightTire, Tire rearLeftTire, Tire rearRightTire,
Seat driversSeat, Seat passengersSeat, Seat rearBenchSeat,
SeatbeltPretensioner seatBeltPretensioner,
Alternator alternator,
Distributor distributor,
Chime chime,
ECM computer,
TireMonitoringSystem tireMonitor
);
public float getSpeed();
}
Comment puis-je utiliser les vertus de l'Injection de Dépendance à l'aide de tests unitaires, tandis que ne pas rompre les vertus de l'encapsulation pour aider à la convivialité?
Voir aussi
- Doit Injection de Dépendance au détriment de l'Encapsulation? (Doit, plutôt que de faire)
Pour l'amour du plaisir, je peux diminuer le getSpeed
exemple pour tout ce qui est nécessaire:
public Car {
public constructor(
Engine engine,
Transmission transmission,
Tire frontLeftTire, Tire frontRightTire
TireMonitoringSystem tireMonitor,
UnitConverter unitsConverter
);
public float getSpeed()
{
float tireRpm = m_engine.CurrentRpm *
m_transmission.GetGearRatio( m_transmission.CurrentGear);
float effectiveTireRadius =
(
(m_frontLeftTire.RimSize + m_frontLeftTire.TireHeight / 25.4)
+
(m_frontRightTire.RimSize + m_frontRightTire.TireHeight / 25.4)
) / 2.0;
//account for over/under inflated tires
effectiveTireRadius = effectiveTireRadius *
((m_tireMonitor.FrontLeftInflation + m_tireMontitor.FrontRightInflation) / 2.0);
//speed in inches/minute
float speed = tireRpm * effetiveTireRadius * 2 * Math.pi;
//convert to mph
return m_UnitConverter.InchesPerMinuteToMilesPerHour(speed);
}
}
Mise à jour: peut-être certaines réponses peuvent suivre la question et de donner un exemple de code?
public Car {
public float getSpeed();
}
Un autre exemple est lorsque ma classe dépend d'un autre objet:
public Car {
private float m_speed;
}
Dans ce cas - float
est une classe qui est utilisée pour représenter une valeur à virgule flottante. De ce que j'ai lu, chaque personne à charge de la classe doit être injecté dans le cas où je veux en moquer float
classe. Cela soulève le spectre d'avoir à injecter chaque membre privé, puisque tout ce qui est fondamentalement un objet:
public Car {
public Constructor(
float speed,
float weight,
float wheelBase,
float width,
float length,
float height,
float headRoom,
float legRoom,
DateTime manufactureDate,
DateTime designDate,
DateTime carStarted,
DateTime runningTime,
Gps gps,
Engine engine,
Transmission transmission,
Tire frontLeftTire, Tire frontRightTire, Tire rearLeftTire, Tire rearRightTire,
Seat driversSeat, Seat passengersSeat, Seat rearBenchSeat,
SeatbeltPretensioner seatBeltPretensioner,
Alternator alternator,
Distributor distributor,
Chime chime,
ECM computer,
TireMonitoringSystem tireMonitor,
...
}
Ce sont vraiment des détails de mise en œuvre que je ne veux pas le client à regarder.