如何在不破坏封装的情况下执行依赖注入?
使用维基百科中的依赖注入示例
public Car {
public float getSpeed();
}注释:其他方法和属性(例如PushBrake()、PushGas()、SetWheelPosition() )省略以求清晰
这很好用;您不知道我的对象是如何实现getSpeed的--它是“封装”的。
实际上,我的对象将getSpeed实现为:
public Car {
private m_speed;
public float getSpeed( return m_speed; );
}一切都很好。有人建造我的Car对象,捣碎踏板,喇叭,方向盘,和汽车响应。
现在,假设我更改了我的car的内部实现细节:
public Car {
private Engine m_engine;
private float m_currentGearRatio;
public float getSpeed( return m_engine.getRpm*m_currentGearRatio; );
}平安无事。Car遵循正确的OO原则,隐藏一些事情是如何完成的细节。这使来电者有时间解决他的问题,而不是试图理解汽车是如何工作的。它也给了我自由地改变我的实现,我认为适合。
但是依赖注入会迫使我将类暴露给我没有创建或初始化的Engine对象。更糟糕的是,我现在暴露了我的Car甚至都有一个引擎:
public Car {
public constructor(Engine engine);
public float getSpeed();
}现在,外边的词知道我使用的是Engine。我并不总是使用引擎,将来我可能不想使用Engine,但是我不能再改变我的内部实现:
public Car {
private Gps m_gps;
public float getSpeed( return m_gps.CurrentVelocity.Speed; )
}不打断来电者:
public Car {
public constructor(Gps gps);
public float getSpeed();
}但是依赖注入打开了一整罐蠕虫:通过打开整个蠕虫罐。依赖注入要求公开我的所有对象的私有实现细节。现在,我的Car类的使用者必须理解并处理我的类以前隐藏的所有内部复杂性:
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();
}我如何利用依赖注入的优点来帮助单元测试,同时又不打破封装的优点来帮助可用性呢?
另请参阅
为了好玩,我可以将getSpeed示例缩减到所需的内容:
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);
}
}更新:--也许某些答案可以跟随问题的线索--并给出示例代码?
public Car {
public float getSpeed();
}另一个例子是当我的类依赖于另一个对象时:
public Car {
private float m_speed;
}在本例中,float是用来表示浮点值的类.根据我所读到的,每个依赖类都应该被注入--以防我想要模拟float类。这引起了必须注入每一个私有成员的恐惧,因为一切从根本上都是一个对象:
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,
...
}这些都是我不想让客户去看的实现细节。
发布于 2010-09-29 16:13:13
这就是我认为您必须使用依赖注入容器的地方,它允许您封装您的car的创建,而不需要让客户端调用者知道如何创建它。symfony是如何解决这个问题的(尽管它不是同一种语言,但原则仍然是一样的):
http://components.symfony-project.org/dependency-injection/documentation
有一节是关于依赖注入容器的。
为了使其简短,并将其全部从文档页面中直接引用:
当使用容器时,我们只要求一个mailer对象--在您的示例中这将是您的车--并且我们不需要再知道如何创建它;关于如何创建mailer car实例的所有知识现在都嵌入到容器中。
希望它能帮助你
https://stackoverflow.com/questions/3823062
复制相似问题