软件设计原则——多用组合少用继承

组合和继承

实现重用的两个途径:白盒和黑盒重用。白盒基于类的继承,但要承受继承的缺点。黑盒基于对象组合。

白盒

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接口。我们想指出的另一个偏好组合的观点是它显式否定继承。在这种情况下,它建议开发者,特别是初级开发者,不要把对象看作设计整个世界的新方式。就面向对象设计而言,关键是这个模型是针对特定问题定制和优化的。有时候,我们倾向于过度抽象,这会产生不够优化的类图。

猜你喜欢

转载自blog.csdn.net/Star_Inori/article/details/83049562