`
simohayha
  • 浏览: 1400004 次
  • 性别: Icon_minigender_1
  • 来自: 火星
社区版块
存档分类
最新评论

ruby way之OOP之二

    博客分类:
  • ruby
阅读更多
1 理解allocate

在一些特殊的环境中,你可能需要不调用它的构造器(也就是initialize)来创建一个对象。也就是说你想要创建一个空的对象.例如,假设你有一个对象,它的状态完全的由它的存取方法所确定,因此如果你不是真的想要一个另外的状态的话,调用new方法是没必要的.此时我们能allocate方法.

class Person
  attr_accessor :name, :age, :phone

  def initialize(n,a,p)
    @name, @age, @phone = n, a, p
  end
  def test
    p "aaa"
  end
end

p1 = Person.new("John Smith",29,"555-1234")

p2 = Person.allocate

p p1.age    # 29
p p2.age    # nil
p2.test


2 Modules

在ruby中使用Modules有两个原因.第一个原因是namespace 的管理,当我们在module中存储常量和方法时,我们将会有更少的命名冲突.调用module中的方法和类方法很类似,就是模块名+方法名.因此我们看到File.ctime 和FileTest.exist?, 时,我们从表面无法知道 File和FileTest是模块还是类.

第二个原因更有趣,我们能使用模块进行mixin.关于什么是mixin,就不说了。

一个模块也能有实例方法,当某个类include了它之后,这些实例方法就变成那个类的了。

module MyMod

  def meth1
    puts "This is method 1"
  end

end


class MyClass

  include MyMod

  # ...
end


x = MyClass.new
x.meth1                # This is method 1


但是如果有一个模块方法时,要怎么办。你可能认为他们被作为类方法来调用。但是ruby没有这种行为。module methods 没有被mixed in。

可是我们如果想要这样使用,我们有一个小技巧.我们可以覆盖一个叫做append_features的方法来实现模块方法的mix.看下面的例子:

module MyMod

  def MyMod.append_features(someClass)
    def someClass.modmeth
      puts "Module (class) method"
    end
    super   # This call is necessary!
  end

  def meth1
    puts "Method 1"
  end

end


class MyClass

  include MyMod

  def MyClass.classmeth
    puts "Class method"
  end

  def meth2
    puts "Method 2"
  end

end


x = MyClass.new

                      # Output:
MyClass.classmeth     #   Class method
x.meth1               #   Method 1
MyClass.modmeth       #   Module (class) method
x.meth2               #   Method 2


这是一个非常有价值的例子.首先我们应当理解append_features 不是一个当include发生时就被调用的hook。它实际上做的是include 操作的工作.这就是为什么super方法在这里是必须的了。没有super。模块剩下的(这里是meth1   )将不会被include.

这里还要注意的是append_features里面定义了一个方法,在ruby中方法内部定义的方法只能是singleton method (也就是说要么是类方法,要么是模块方法).如果你尝试着定义一个实例方法,就会抛出一个Nested method error.

有时一个模块可能想要决定一个mixin的发起类。append_features 也可以做这个,因为它的参数就是那个类.

我们其实也可以mix一个实例方法,作为类方法:

module MyMod

  def meth3
    puts "Module instance method meth3"
    puts "can become a class method."
  end

end


class MyClass

  class << self    # Here, self is MyClass
    include MyMod
  end

end


MyClass.meth3

# Output:
#   Module instance method meth3
#   can become a class method.


如果我们使用extend,代码就变成这样了:

class MyClass
    extend MyMod
end


我们这里谈论的都是方法,那么实例变量呢,它能被mix吗。尽管模块拥有自己的实例数据是可能的,可是经常都不需要这样做.

mix一个模块到一个对象,也是可以操作的。后面我们会介绍.

我们可以mix Comparable模块 和定义<=> 方法。这样的话我们就能使用<, >, <=, 这样的操作.

3 转换一个对象

这张其实前面几张都有了。比如to_s和to_str的区别,比如coerce的使用。因此这边就简要的介绍下了.

看下面的例子

class String

  def coerce(n)
    if self['.']
      [n, Float(self)]
    else
      [n, Integer(self)]
    end
  end
end

x = 1 + "23"        # 24
y = 23 * "1.23"     # 29.29


也就是说调用*或者+的时候会将字符串转换,而数字将不会做任何动作.

4 创建一个只有数据的类(Structs)

可能你想这样做:

class Address

  attr_accessor :street, :city, :state

  def initialize(street1, city, state)
    @street, @city, @state = street, city, state
  end

end

books = Address.new("411 Elm St", "Dallas", "TX")


虽然这样也可以做,可是他太丑陋了。在ruby中,我们有Struct 来做这个事.我们能够这样使用Struct:

Address = Struct.new("Address", :street, :city, :state)
books = Address.new("411 Elm St", "Dallas", "TX")


那么new方法的第一个参数的意思是什么呢?当我们调用Struct.new创建一个新的structure template 时,一个新的类就通过Struct 类他自己被创建。这个类的名字就是第一个参数的内容。因此我们还能这样做:

Struct.new("Address", :street, :city, :state)
books = Struct::Address.new("411 Elm St", "Dallas", "TX")


当你创建一个structure 的实例的时候不一定要把所有的变量都写上,当你调用new时,忽略的变量,它会默认为nil。

这里的话,不要创建一个名叫Tms的Struct,因为Struct内置了一个Tms的类。

5 冻结对象

我们如果想要保护一个对象不被改变,这时我们能使用freeze 方法。

str = "This is a test. "
str.freeze

begin
  str << " Don't be alarmed."   # Attempting to modify
rescue => err
  puts "#{err.class} #{err}"
end

arr = [1, 2, 3]
arr.freeze

begin
  arr << 4                      # Attempting to modify
rescue => err
  puts "#{err.class} #{err}"
end

# Output:
#   TypeError: can't modify frozen string
#   TypeError: can't modify frozen array


但是这里注意的是freeze 操作的是对象的引用,而不是那个变量。请看下面的例子:

str = "counter-"
str.freeze
str += "intuitive"       # "counter-intuitive"

arr = [8, 6, 7]
arr.freeze
arr += [5, 3, 0, 9]      # [8, 6, 7, 5, 3, 0, 9]


这里可以看到str使用+=之后创建了一个新的对象,这时str指向了新的对象,因此新的对象并没有被冻结,而老的对象依旧被冻结了。

frozen? 方法返回一个对象是否被冻结.
hash = { 1 => 1, 2 => 4, 3 => 9 }
hash.freeze
arr = hash.to_a
puts hash.frozen?                   # true
puts arr.frozen?                    # false
hash2 = hash
puts hash2.frozen?                  # true









2
0
分享到:
评论

相关推荐

    Addison Wesley The Ruby Way 2Nd Edition Oct 2006.pdf(英文版)

    ### Addison Wesley《The Ruby Way》第二版(2006年10月) #### 书籍概览 《The Ruby Way》是由Hal Fulton编写的关于Ruby编程语言的经典著作,该书的第二版出版于2006年10月,由Addison Wesley Professional出版社...

    prototype_oop_javascript_ruby_prototype_

    标题 "prototype_oop_javascript_ruby_prototype_" 暗示了我们将探讨的是关于原型(Prototype)面向对象编程(Object-Oriented Programming, OOP)的概念,主要关注JavaScript和Ruby这两种语言之间的相似性和差异性...

    grawing_way_oop

    本文将深入探讨"grawing_way_oop"这一主题,它可能是一个关于使用C++进行面向对象编程的实践项目,其中涉及到CMake.txt配置文件的修改,以适应项目构建需求。 首先,我们来理解面向对象编程的核心概念。面向对象...

    2014年辛星PHP教程秋季版之OOP与MVC.pdf

    2.之所以说 oop 是一种思想,是因为很多编程语言对它的具体实现 上还是有较大的不同的。比如 python 中函数和变量也都是对象, Javascript 中有很多的伪对象,Java 则是完全的面向对象,而 Java 和 PHP 等语言都只能...

    From Java to Ruby

    Ruby的块和闭包是其独特之处,它们提供了强大的控制流和数据处理能力,这是Java中匿名内部类和接口不能比拟的。 其次,Ruby的语法简洁明了,例如,方法调用可以省略括号,变量声明不需要特定关键字,这使得代码看...

    learn_oop_ruby:启动School Ruby OOP教程

    在Ruby编程语言中,面向对象编程(Object-Oriented Programming, OOP)是一种核心特性,它使得代码更加结构化和可重用。"learn_oop_ruby:启动School Ruby OOP教程"是一个针对初学者的资源,旨在帮助他们掌握Ruby中的...

    浅谈OOP之uml设计模式

    **OOP之UML设计模式概述** 面向对象编程(Object-Oriented Programming,简称OOP)是一种编程范式,它以对象为中心,强调数据和操作数据的方法,通过封装、继承和多态等特性来实现软件的模块化和可扩展性。在OOP中...

    倍福OOP2_Count.tpzip

    倍福OOP2_计数器程序

    ruby-event-oop

    2. **事件监听和处理**:在Ruby中,可以定义类和对象来监听特定的事件,并定义方法作为事件处理器。例如,可以创建一个Server类,该类实例监听TCP连接请求,接收到连接事件后,调用处理连接的方法。 3. **线程和 ...

    Ruby编程Ruby Programming

    ### 二、Ruby编程基础 #### 2.1 变量与数据类型 - **变量**:Ruby中的变量无需声明类型,直接赋值即可使用。例如:`name = "John Doe"`。 - **数据类型**: - 字符串(String) - 数组(Array) - 哈希(Hash) ...

    ruby 经典教程从新手到专家

    - **面向对象编程(OOP)**:详细解释Ruby中的类、对象、继承、封装、多态等OOP核心概念。 - **程序结构**:探讨模块、混合和命名空间,如何组织大型Ruby项目。 #### 第二部分:进阶技巧 - **元编程**:讲解Ruby的元...

    s2 JavaOOP上机作业全部代码

    2. **封装**:封装是将数据和操作数据的方法绑定在一起的过程,保护数据不被外部直接访问。在Java中,通过使用访问修饰符(public, private, protected)来实现封装。例如,你可以将Car类的发动机型号设为私有,只...

    oop实践

    **OOP实践** 面向对象编程(Object-Oriented Programming,简称OOP)是一种软件开发方法,它基于对象、类和消息传递的概念,旨在提高代码的重用性、可维护性和可扩展性。在实际的软件开发中,OOP是解决复杂问题的...

    Java OOP编程思想学习之我见

    ### Java OOP编程思想学习之我见 在深入探讨Java面向对象编程(OOP)之前,我们首先要理解OOP的基本概念及其与过程式编程的区别。Java作为一种强大的编程语言,其设计初衷之一就是全面拥抱OOP理念,这不仅体现在...

    eloquent ruby

    2. **面向对象编程(OOP)** - Ruby是一种纯面向对象的语言,一切皆对象。 - 类(Class)与实例(Instance)的概念。 - 继承(Inheritance)与多态(Polymorphism)。 - Ruby的元编程特性,如模块(Module)和混入(Mixins)等...

    PHP OOP入门必读

    "PHP5面向对象初步(第二章).php"可能涉及封装的概念,这是OOP的四大特性之一。封装允许我们将数据和操作这些数据的方法绑定在一起,保护内部数据不受外界干扰。通过访问修饰符(如public、private、protected),...

    JavaOOP.xmind

    java oop,适合小白。

    javascript oop模式讲解

    2. **原型对象**:每个构造函数都有一个`prototype`属性,它是对象的原型,可以添加方法和属性。这些属性和方法将被所有该构造函数的实例共享。例如: ```javascript Person.prototype.greet = function() { ...

Global site tag (gtag.js) - Google Analytics