• 泛型与继承


    泛型和继承是现代编程语言中两种比较重要的特性,对提高语言的表达能力,增强软件的质量、健壮性、可维护性有重要作用。前者常见于函数式编程语言,如Haskell;后者则是面向对象(OO)语言的基础。泛型对类型的描述更细化,表达能力更强,然而,泛型是编译期的信息,无法提供像继承中的动态绑定功能,这也许是过去二十年中OO语言得到广泛使用的原因。

    之所以说泛型不能实现动态的效果,主要原因在于:

    1) 泛型信息仅仅在编译期起作用
    2) 泛型不支持类型的向下转换(Down Casting),即子类对象转换成作为父类型使用
    

    这使得泛型在实现类似虚函数的多态时,无法实现或者极为麻烦。考虑如下的情况

    class Animal:
        method eat ...
    
    class Cat inherite Animal:
        method eat ...
    
    class Dog inherite Animal:
        method eat ...
    

    这在OO中是很常见、很基本的。然而如果用泛型实现,则很麻烦。比如用Pattern Matching

    func eat animal:
        Cat cat = ...
        Dog dog = ...
    

    调用时

    eat(cat, ...)
    eat(dog, ...)
    

    似乎也可以。但是,如果catdog是由某个Factory根据配置文件动态产生的,也就是

    cat = Factory.create_animal ...
    

    现在create_animal的返回值类型如何写?显然,由于泛型中不能将CatDog都转换成父类Animal来处理,就无法在运行时依据animal的实际类型,调用对应的函数;而必须在编译期确定所有的类型和应当调用的函数。

    无法进行动态绑定,也就无法进行软件的动态扩展。比如,在Java中,上述代码已经打包成Jar包,现在要增加一个类型Pig,我们只需让Pig继承Animal,将新代码打成Jar包即可使用,无需对原有的代码进行改动和编译。而对于泛型的版本而言,不但无法实现动态扩展,而且还要修改原始的eat函数,加入Pig对应的Pattern代码。

    这一特性使得OO语言能够很好的支持“开闭”原则,即代码对扩展开放,对修改封闭。通常人们认为,OO的优势在于对现实世界中“对象”的模拟,但是我更认同松本行弘的观点,即:如同结构化编程一样,OO是一种代码组织的方式,使得软件开发中的复杂度能够得到更好的控制,至于它是否模拟了世界,并不重要。

    在我开来,OO的作用是把接口和实现分离,并且将实现的函数体拆分到了多处。在上述例子中,增加了Pig类型,实际上是在eat函数中增加了功能,能够处理Pig类型的变量。从另一个角度说,多态的eat函数等价于

    eat animal, ...:
    
        if animal instance of Cat:
            ...
        elif animal instance of Dog:
            ...
    

    加入了Pig类型,等于增加了一个if分支:

        elif animal instance of Pig:
            ...
    

    而这种增加,既没有改变接口,也不需要修改原来的代码,而是通过类的继承。所以,通过类型继承实现的多态,在不改变接口的前提下,把实现函数的函数体根据具体类型拆分到了多处,并且可以增加新的部分,而不影响原有部分。这显然就是对“开闭”原则的实践。

    “开闭”原则对提高软件的可扩展性,控制复杂性有重要作用,在大型软件开发中尤为明显。过去20年间,C++、Java等OO语言获得了广泛使用。而Haskell、Lisp、Erlang等语言尽管更清晰、简洁,有更好的数学基础,或者并发的效率更高,但是却没有获得广泛的普及。仅仅把原因归咎于曲高和寡是不够的。在作者看来,这些函数式语言因为无法提供类型继承和动态绑定的功能,导致不能很好的支持开闭原则,在大型软件开发中不能很好的控制复杂度,是它们没有获得广泛应用的主要原因,尤其是在应对需求复杂多变的场合方面。

  • 相关阅读:
    一些牛逼的统计SQL
    一个有趣的 SQL 查询(查询7天连续登陆)
    Highcharts-3.0.6
    linux 下载并安装Memcache服务器端
    nginx + tomcat集群和动静资源分离
    C#中使用SendMessage在进程间传递数据的实例
    Wparam与Lparam的区别
    WPARAM和LPARAM的含义
    C# 使用SendMessage 函数
    在WinForm中使用Web Services 来实现 软件 自动升级( Auto Update ) (C#)
  • 原文地址:https://www.cnblogs.com/aquastone/p/generic_inherite.html
Copyright © 2020-2023  润新知