《Effective Ruby:改善Ruby程序的48条建议》一第8条:初始化子类时调用super

第8条:初始化子类时调用super

Ruby中,类没有传统的OOP式的构造方法。如果想要控制对象的初始状态,我们得写一个名为initialize的方法并在那里做必要的工作。在一个新对象被分配空间之后,就会在new中调用这个方法。如果你不在自己的类中自定义initialize方法,你的类将从BasicObject类中继承默认实现。不过这并不那么有效。事实上,那是个空方法,什么也没做。它只是在那里,使得new方法在你没有自定义initialize方法时有处可调。还好,很多时候BasicObject#initialize就可以满足你的需要了。不过当你需要自定义initialize方法时是个小例外。
有一点特别容易被忽略,initialize方法其实只是一个常规的私有实例方法,因此它遵循所有常规方法搜索规则。比如,如果你想,你能定义reset方法来简单地调用initialize方法把所有实例变量重设为其初始值。不过把initialize方法作为常规方法调用会造成令人惊讶的结果。当你定义initialize方法时你也重载了所有在继承体系中其他更高层的initialize的定义。如果在你曾用过的语言中存在正式的构造方法,你可能希望所有的继承体系中的方法会链在一起而非相互重载。不过在Ruby中和你想得不太
一样:

来看方法Parent#initialize,很容易看出,当创建一个新的Parent对象时,实例变量@name会被初始化为一个默认值。也很容易看出当创建一个Child时,方法Child#initialize会为实例变量@grade赋值。可能不清楚的问题就是,创建一个Child对象是否也能为@name赋初始值。在IRB中运行这些代码就可以搞清楚这个问
题了:

啊!Ruby不能自动调用被重载的方法,即使在initialize方法中也不行。本例中Child::new没有调用Parent类里的initialize方法,因为Child类有自己的initialize方法,它重载了父类的这个方法。重写带参的initialize方法将使事情更清楚些。

如今你能看到这个窘境了。Ruby没有为我们提供给子类和其超类的initialize方法建立联系的方式。因此没办法知道如何自动调用超类中的initialize方法并传递正确的参数。于是这个任务留给了我们。这对新手Ruby程序员来说是件令人惊讶的事情,甚至老手也会不一定记得。
既然Ruby不会为我们初始化父类,我们该如何完成它呢?为initialize方法准备的解决方案和重载其他方法一样。也就是说,我们可以使用通用意义上的super关键字来调用继承体系中位于高层的方法。

在放弃了自动构造方法的同时我们获得了灵活性。使用super调用超类的initialize方法让我们拥有了如何初始化超类以及在什么时候初始化超类的控制权。超类应该在子类之前初始化吗?在初始化超类之前我们需要设置一些环境变量吗?我们可以自由地按照需要安排这些行为。只要记住用super就行,花点时间复习一下super的各种用法吧,见第7条。
在总结之前,我得提醒你initialize不是构建新对象的唯一方式。Ruby允许我们使用dup和clone方法创建对象的副本。当你使用这些方法中任一个时,可以通过定义initialize_copy方法对新创建的副本对象执行一些特别的逻辑。如果你从超类重载initialize_copy方法,你一定想使用super来正确地构建它。
要点回顾
当创建子类对象时,Ruby不会自动调用超类中的initialize方法。作为替代,常规的方法查询规则也适用于initialize方法,只有第一个匹配的副本会被调用。
当为显式使用继承的类定义initialize方法时,使用super来初始化其父类。在定义initialize_copy方法时,应使用相同的规则。

时间: 2024-09-26 08:25:08

《Effective Ruby:改善Ruby程序的48条建议》一第8条:初始化子类时调用super的相关文章

编写高质量代码改善C#程序的157个建议[IEnumerable<T>和IQueryable<T>、LINQ避免迭代、LINQ替代迭代]

原文:编写高质量代码改善C#程序的157个建议[IEnumerable<T>和IQueryable<T>.LINQ避免迭代.LINQ替代迭代] 前言 本文已更新至http://www.cnblogs.com/aehyok/p/3624579.html .本文主要学习记录以下内容: 建议29.区别LINQ查询中的IEnumerable<T>和IQueryable<T> 建议30.使用LINQ取代集合中的比较器和迭代器 建议31.在LINQ查询中避免不必要的迭代

编写高质量代码改善C#程序的157个建议[为泛型指定初始值、使用委托声明、使用Lambda替代方法和匿名方法]

原文:编写高质量代码改善C#程序的157个建议[为泛型指定初始值.使用委托声明.使用Lambda替代方法和匿名方法] 前言 泛型并不是C#语言一开始就带有的特性,而是在FCL2.0之后实现的新功能.基于泛型,我们得以将类型参数化,以便更大范围地进行代码复用.同时,它减少了泛型类及泛型方法中的转型,确保了类型安全.委托本身是一种引用类型,它保存的也是托管堆中对象的引用,只不过这个引用比较特殊,它是对方法的引用.事件本身也是委托,它是委托组,C#中提供了关键字event来对事件进行特别区分.一旦我们

编写高质量代码改善C#程序的157个建议[用抛异常替代返回错误、不要在不恰当的场合下引发异常、重新引发异常时使用inner Exception]

原文:编写高质量代码改善C#程序的157个建议[用抛异常替代返回错误.不要在不恰当的场合下引发异常.重新引发异常时使用inner Exception] 前言 自从.NET出现后,关于CLR异常机制的讨论就几乎从未停止过.迄今为止,CLR异常机制让人关注最多的一点就是"效率"问题.其实,这里存在认识上的误区,因为正常控制流程下的代码运行并不会出现问题,只有引发异常时才会带来效率问题.基于这一点,很多开发者已经达成共识:不应将异常机制用于正常控制流中.达成的另一个共识是:CLR异常机制带来

编写高质量代码改善C#程序的157个建议[4-9]

原文:编写高质量代码改善C#程序的157个建议[4-9] 前言 本文首先亦同步到http://www.cnblogs.com/aehyok/p/3624579.html.本文主要来学习记录一下内容: 建议4.TryParse比Parse好 建议5.使用int?来确保值类型也可以为null 建议6.区别readonly和const的使用方法 建议7.将0值设为枚举的默认值 建议8.避免给枚举类型的元素提供显式的值 建议9.习惯重载运算符 建议4.TryParse比Parse好 如果注意观察,除st

编写高质量代码改善C#程序的157个建议[C#闭包的陷阱、委托、事件、事件模型]

原文:编写高质量代码改善C#程序的157个建议[C#闭包的陷阱.委托.事件.事件模型] 前言 本文已更新至http://www.cnblogs.com/aehyok/p/3624579.html .本文主要学习记录以下内容: 建议38.小心闭包中的陷阱 建议39.了解委托的实质 建议40.使用event关键字对委托施加保护 建议41.实现标准的事件模型 建议38.小心闭包中的陷阱 首先我们先来看一段代码: class Program { static void Main(string[] arg

编写高质量代码改善C#程序的157个建议[为类型输出格式化字符串、实现浅拷贝和深拷贝、用dynamic来优化反射]

原文:编写高质量代码改善C#程序的157个建议[为类型输出格式化字符串.实现浅拷贝和深拷贝.用dynamic来优化反射] 前言 本文已更新至http://www.cnblogs.com/aehyok/p/3624579.html .本文主要学习记录以下内容: 建议13.为类型输出格式化字符串 建议14.正确实现浅拷贝和深拷贝 建议15.使用dynamic来简化反射实现 建议13.为类型输出格式化字符串   有两种方法可以为类型提供格式化的字符串输出. 一种是意识到类型会产生格式化字符串输出,于是

编写高质量代码改善C#程序的157个建议[匿名类型、Lambda、延迟求值和主动求值]

原文:编写高质量代码改善C#程序的157个建议[匿名类型.Lambda.延迟求值和主动求值] 前言 从.NET3.0开始,C#开始一直支持一个新特性:匿名类型.匿名类型由var.赋值运算符和一个非空初始值(或以new开头的初始化项)组成.匿名类型有如下基本特性: 1.既支持简单类型也支持复杂类型.简单类型必须是一个非空初始值,复杂类型则是一个以new开头的初始化项. 2.匿名类型的属性是只读的,没有属性设置器,它一旦倍初始化就不可更改. 3.如果两个匿名类型的属性值相同,那么就任务这两个匿名类型

编写高质量代码改善C#程序的157个建议[动态数组、循环遍历、对象集合初始化]

原文:编写高质量代码改善C#程序的157个建议[动态数组.循环遍历.对象集合初始化] 前言   软件开发过程中,不可避免会用到集合,C#中的集合表现为数组和若干集合类.不管是数组还是集合类,它们都有各自的优缺点.如何使用好集合是我们在开发过程中必须掌握的技巧.不要小看这些技巧,一旦在开发中使用了错误的集合或针对集合的方法,应用程序将会背离你的预想而运行. 本文已更新至http://www.cnblogs.com/aehyok/p/3624579.html .本文主要学习记录以下内容: 建议16.

编写高质量代码改善C#程序的157个建议[10-12]

原文:编写高质量代码改善C#程序的157个建议[10-12] 前言 本文已更新至http://www.cnblogs.com/aehyok/p/3624579.html .本文主要学习记录以下内容: 建议10.创建对象时需要考虑是否实现比较器 建议11.区别对待==和Equals 建议12.重写Equals时也要重写GetHashCode 建议10.创建对象时需要考虑是否实现比较器 有对象的地方就会存在比较,就像小时候每次拿着考卷回家,妈妈都会问你隔壁的那谁谁谁考了多少分呀.下面我们也来举个简单