组合和继承
实现重用的两个途径:白盒和黑盒重用。
白盒基于类的继承,但要承受继承的缺点。黑盒基于对象组合。
白盒
public class RegisteredUser : User
{
...
}
继承的缺点
派生类继承了父类的上下文,获得父对象状态的某种可见性。随着不同版本派生类的出现,并不能保证父类和派生类真的可以交替使用。保证父类及其派生类可以交替使用是里氏代换原则的目标。
黑盒
public class RegisteredUser
{
private User theUser;
public RegisteredUser()
{
// 可以使用延迟加载策略来实例化
theUser = new User();
}
public object DoWork()
{
var data = theUser.DoSomeWork();
return Progress(data);
}
private object Process(object data)
{
...
}
}
对象组合示例
派生类(RegisteredUser)以黑盒的方式使用基类(User)类型。RegisteredUser不能访问User的内部成员,也不能以任何方式改变它的行为,它使用这个对象而不是改变这个对象来实现它的目标。外部调用到达包装类,包装类把这个调用委托给内部持有的类的实例。
RegisteredUser和User的关系
把包装类和被包装的类连在一起的逻辑是由你来决定的。你决定User类的哪个部分应该暴露出去,以及如何暴露出去。派生成:RegisteredUser,基类:User
对象组合的好处
组合有一个关键的好处没有办法通过继承得到:它是一种防御式编程(DefensiveProgramming),就这一点而论,更难引入与面向对象里广为人知的糟糕实践有关的细微缺陷,如脆弱的基类、虚成员和构造函数。
组合起来的两个类没有明显的关系;你不能在需要User实例的地方使用RegisteredUser类。如果最后证明这是一个问题,你可以让两个类实现某个通用的IUser接口。我们想指出的另一个偏好组合的观点是它显式否定继承。在这种情况下,它建议开发者,特别是初级开发者,不要把对象看作设计整个世界的新方式。就面向对象设计而言,关键是这个模型是针对特定问题定制和优化的。有时候,我们倾向于过度抽象,这会产生不够优化的类图。