Ruby面向对象编程中类与方法的基础学习
打开类和猴子补丁 class Example def method_1 puts "method 1" end end class Example def method_2 puts "method 2" end end 本例中,当第一次定义Class Example的时候,还没有一个叫做Example的Class存在,因此,Ruby开始定义这个类,当后面在定义这个类时,Ruby会发现该类已存在,并返回这个类,而不是定义一个新类。 因为这个特性,因此,Ruby天生具有打开一个已经存在的类,并动态修改其内容的能力,即使其是标准类库的类也不例外。比方说,可以给SDK的String类添加一个去除String中的标点符号和特殊字符的方法:to_alphanumeric class String def to_alphanumeric gsub /[^ws]/,'' end end “H&&^^ello”.to_alphanumeric #==>Hello ,然后,所有的String对象都具备“to_alphanumeric”的能力了,这种技术一般简称为打开类技术。 上面描述的打开类技术其实是隐含了一定的风险的,尤其是在大型系统中使用打开类技术扩展标准类库时,因为,很多开发人员都在扩展类,当多个扩展方法的名字一样时, 后定义的总会覆盖掉前面,从而导致整个系统的崩溃,业界把这种鲁莽的修改类的方式简称为猴子补丁(Monkey Patch)。因此在使用打开类技术时,一定要慎之又慎。 实例变量 class Person def name @name = "xianlinbox" end end p = Person.new puts p.instance_variables #==>nil p.name puts p.instance_variables #==>@name 方法 如果要定义类方法,那么在定义方法的时候,必须加类名前缀,如下: class Person def Person.name @name = "xianlinbox" end end 类本身也是对象 puts "hello".class #=> String puts String.class #=> Class puts Class.class #=> Class puts Class.instance_methods(false) #=> [:superclass,:allocate,:new] puts Class.instance_variables #=> nil 类的继承体系 puts String.superclass #=> Object puts Class.superclass #=> Module puts Module.superclass #=> Object puts Object.superclass #=> BasicObjec puts BasicObject.superclass #=> nil BasicObject是继承体系的根节点。 方法的查找与执行 String.ancestors # => [String,Comparable,Object,Kernel,BasicObject] 为什么这儿会出现Comparable和Kernal, 这是因为Module的机制,当一个类include一个模块时,编译会把该模块放在最靠近该类的祖先链上, String类include了Comparable模块,而Kernal则是被Object类include的。 方法执行的时候需要一个接收者,方法就会在接收者对象中被执行,该接收者就是所谓的self对象。一般情况下,self对象是由最后一个接收该方法的对象担当,在类和模块的定义中(并且在任何方法的定义外),self对象由类或模块担任。 动态调用方法 config.name = v if isNameProperty?(k) config.password = v if isPasswordProperty?(k) config.port = v if isPortProperty?(k) ... 看着这么一堆的长得像亲兄弟似的代码,不由得产生一种阉掉它们的冲动。如果使用动态调用方法的话,代码可以简化如下: load_config('config.properties').each do |k,v| config.send("#{k}=",v) end 根据获取的每个键值,去调对应属性的set方法,代码清爽很多,而且以后扩展config对象不需要修改load方法。 动态定义方法 class MyClass define_method :doubleString do |args| args * 2 end end t = MyClass.new puts t.doubleString("he") # => hehe 有了这个黑魔法之后,以后,就可以多个相似方法中不同的部分抽出来作为参数,然后,使用一个方法定义搞定所有的方法。 method_missing()方法 但是,我们可以覆写这个方法,让它变得很有意思。比方说,创建一个Struct,当你想要新的属性时,只需要给它赋个值就神奇的产生了。 class MyStruct def initialize @attributes = {} end def method_missing(name,*args) attribute = name.to_s if attribute =~ /=$/ @attributes[attribute.chop] = args[0] else @attributes[attribute] end end end s = MyStruct.new s.weibo = "@xianlinbox" puts s.weibo # => @xianlinbox 这种,从调用者角度看,跟普通方法没什么区别,但是实际接收者却并没有相对应的方法的方法,Ruby术语称之为幽灵方法(Ghost Method)。对于幽灵方法,除了自定义该方法以外,还可以把该方法转发给另外一个对象的方法,当然,你可以在转发前后包装一些自己的逻辑,这种处理技术称之为动态代理(Dynamic Proxy),和前面提到的动态调用异曲同工。 使用了method_missing处理幽灵方法后,所有不存在方法的调用都会到这里来,这可能会导致一些错误信息不直观的问题(你看不到NoSuchMethod这样的提示了),因此, 在使用method_missing方案的时候,一定要限定其使用范围,并且调用父类的super.method_missing方法,让不属于这个范围的,该报什么错还是报什么错。 白板类与保留方法 在Ruby的Object类中,有一些方法是内部使用的,如果对其重新定义,或删除,可能导致Ruby莫名其妙的挂掉,为了防止这种事情的发生,Ruby在这些方法名前面用“__”打头,这些方法称之为保留方法,当你试图修改这些方法时,Ruby会给出警告。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |