`

Programming Ruby(读书笔记)-3章

    博客分类:
  • Ruby
 
阅读更多

Classes,Objects,and Variables

everything we manipulate in Ruby is an object.And every object in Ruby was generated either directly or indirectly from a class.所有操作都是对象操作,对象是由类直接或者间接产生。为更生动描述类与对象,先设一个案例场景,一个二手书店,每天员工要统计书的信息,比如拿着扫描器扫描每个书的条形码...现在产生如下的数据在CSV文件中:

tut_classes/stock_stats/data.csv

"Date","ISBN","Price"

"2013-04-12","978-1-9343561-0-4",39.45

"2013-04-13","978-1-9343561-6-6",45.67

"2013-04-14","978-1-9343560-7-4",36.95

,我们定义BookInStock

 

class BookInStock
  def initialize(isbn, price)  //initialize是Ruby的回调,会在调用new的时候调用
    @isbn = isbn    #@开始的是instance variables实例变量
    @price = Float(price) #将入参转换为float类型,如果转换出错就抛出异常
  end
end

b1 = BookInstock.new('isbn1', 1)
p b1
b2 = BookInstock.new('isbn2',2.2)
p b2
b3 = BookInstock.new('isbn3', '1.23')
p b3
produces:
#<BookInStock:0x007fac4910f3e0 @isbn="isbn1", @price=3.0>
#<BookInStock:0x007fac4910f0c0 @isbn="isbn2", @price=3.14>
#<BookInStock:0x007fac4910eda0 @isbn="isbn3", @price=5.67>

注意:上面是使用p而不是puts,如果使用puts则只打印#<BookInStock:0x007fac4910f3e0>,因为puts只是简单的把string内容输出到标准输出,而传入我们定义的类时,它只会把类名称和类的id打印出来。这类似于java的toString方法,需要覆盖,来吧,再敲一遍

 

 

class BookInStock
  def initialize(isbn, price)
    @isbn = isbn
    @price = price
  end

  def to_s
    "ISBN: #{@isbn}, price:#{@price}" #实例变量可被所有类方法使用
  end
end

 -----------Attributes------------------

 

类实例生成后,保存了自己的状态(java里的成员变量的值,在此被描述为内部状态(internal state)),默认情况下这些内部状态其它类不能触碰。为了能与外界进行状态交互,引用了attributes(属性)的概念:These externally visiable facets of an object are called attributes。不过概念不重要。

 

class BookInStock
  ...
  def isbn
    @isbn
  end
  def price
    @price
  end
.....
book = BookInStock.new('ruby', 1.23)
puts "ISBN:#{book.isbn}"
produces:
ISBN:ruby

 Ruby为这种情况提供了便捷方式:

class BookInStock
  attr_reader :isbn, :price         #这里使用的是符号
  ...........
end

符号是方便引用名称,这里“:isbn”表示isbn的名称,而“isbn”则表示isbn的值。 如果有些绕,想想不使用符号,那写成什么?

注意:attr_reader并不是实例变量的声明,它是创建了获取方法,变量本身是没有声明,Ruby解耦实例变量与获取方法,如吧,这个我也有些不明白,原文:

It creates the accessormethods, but the variables themselves don’t need to be declared

—they just pop into existence when yo u use them. Ruby completely decouples instance

variables and accessor methods, as we’ll see in Virtual Attributes, on page 35.

----------Writable Arributes--------

#可修改价格的类
class BookInStock
  attr_reader :isbn, :price

  def initialize(isbn, price)
    @isbn = isbn
    @price = price
  end
  def price=(new_price) #定义了price=方法,setPrice(new_price)也行,只是调用要去掉=
    @price = new_price
  end
end

 同样,Ruby为些提供了attr_accessor,attr_accessor :price会给类创建两个方法price与price=,一个用于获取值,一个用于设置新值。

 

有个问题:可以自定义获取属性的名称吗?比如类中定义的price,希望外界使用book_price

------------Virtual Attributes----------------

class BookInStock
  attr_reader :isbn
  attr_accessor :price
  def initialize(isbn, price)
    @isbn = isbn
    @price = price
  end
  def price_in_cents
    Integer(price*100 + 0.5)       #这里没有使用@price
  end
  def price_in_cents=(cents)      #定义写方法是添加一个=
    @price = cents/100.0
  end
end

 --------Attributes,Instance Variables, and methods---------

 Attribute就是方法,只是它被用于存取实例变量相关的内容。

The external state is exposed through methods we’re calling attributes. And the

other actions your class can perform are just regular methods. It really isn’t a crucially

important distinction, but by calling the external state of an object its attributes, you’re

helping clue people in to how they should view the class you’ve written.

-------------Classes Working with Other Classes-------------------

class CsvReader
  def initialize
    @books_in_stock = []
  end
  
  def read_in_csv_data(csv_file_name)
    CSV.foreach(csv_file_name, headers: true) do |row|
      @books_in_stock << BookInStock.new(row["ISBN"], row["Price"])
    end
  end
end

 headers: true表示解析第一行作为为列的名称。

--------------下面使用一个实例描述多个类之间的交互---------------------

实例代码见附件:stock_stats.rar

-----------访问控制---------------

a good rule of thumb(好的经验法则):不要提供那些能使类的状态出现不正确的方法。Ruby提供三个保护级别:Public/Protected/Private

Public:默认级别,但是initialize除外

Protected:只有类对象或子类对象可访问

Private:不允许object.privateMethod的调用(explicit receiver),只允许在当前类对象的上下文内调用。与其java不现的是,同一类型的两个对象A,B,B不能这样使用A.privateMethod。想想java的equals方法。

Ruby的访问级别可以在程序动态修改:

Ruby differs fromotherOOlanguages in another importantw a y .Access control is determined

dynamically, as the program runs, not statically. Y o u will get an access violation only when

the code attempts to execute the restricted method.

两种方式设置级别:(级别应用在方法和模块上)

1、

class Class1
public
  def function1
  end
end

 

2、

class Class2
  def function1
  end
  ....
  public :function1,:function2
  protected :function3
end

 模拟一个转账的示例,使用了访问级别

class Account
  attr_accessor :balance
  
  def initialize(balance)
    @balance = balance
  end
end

class Transaction
  def initialize(account_a, account_b)
    @account_a = account_a
	@account_b = account_b
  end
  
private
  def debit(account, amount)
    account.balance -= amount
  end
  def credit(account, amount)
    account.balance += amount
  end

public
  def transfer(amount)
    debit(@account_a, amount)
	credit(@account_b, amount)
  end
end

account_a = Account.new(100)
account_b = Account.new(50)
trans = Transaction.new(account_a, account_b)
trans.transfer(50)
puts "After transfer, account_a's balance #{account_a.balance},account_b's balance #{account_b.balance}"

 protected级别用于,同种类型的对象互相访问内部状态,比如:

class Account
  attr_reader :cleared_balance  #定义cleared_balance访问方法
  protected :cleared_balance     #控制访问级别

  def greater_balance_than?(other)
    @cleared_balance > other.cleared_balance
  end
end

 ---------3.4变量-------------

Ruby中

person = "Time" #person并不是一个对象,而只是一个引用,即变量不是个对象,只是一个引用。这个与JAVA一样。

person2 = person,再修改person2的内容,person也会被修改,两个引用指向同一个对象。

通过person3 = person.dup,可clone一个新的对象。也可以通过调用person.freeze来阻止被修改。

 

 

 

 

 

 

 

 

 

分享到:
评论

相关推荐

    Ruby学习资料(含参考手册和Programming Ruby)-中文.rar

    "ruby--.txt"可能是一个文本文件,其中包含了Ruby的代码示例、笔记或者问题解答,通过阅读可以加深对Ruby语法和实践的理解。 "Ruby语言入门教程附实例"和"ruby-mht"文件很可能是包含实例的教程,实践是学习编程的...

    ruby初学笔记ruby初学笔记

    1. **面向对象编程(Object-Oriented Programming, OOP)**:Ruby是完全的面向对象语言,每个值都是一个对象,包括基本类型如整数、字符串和布尔值。类是创建对象的蓝图,实例化一个类就能创建一个新的对象。理解类...

    Ruby 语言教程从小白到入门

    首先,Ruby的核心概念是面向对象编程(Object-Oriented Programming, OOP)。在Ruby中,一切都是对象,包括基本的数据类型如数字、字符串和布尔值。理解这一点至关重要,因为这意味着你可以对任何东西调用方法,这极...

    programming_language:编程语言学习笔记

    "programming_language:编程语言学习笔记"这一主题旨在整理和探讨各种编程语言的关键特性、语法结构以及在实际开发中的应用。 首先,编程语言可以分为几大类别,如低级语言(机器语言和汇编语言)和高级语言(如C,...

    java俄罗斯方块源码-ossu-cs:通过开源社会大学开设的计算机科学课程

    java俄罗斯框源码开源社会大学 计算机科学课程 罗伯特·福克 核心模块 C100 - 计算机科学课程简介 涵盖的主题: computation imperative programming ...笔记 ...programming ...Ruby 代码 班级 笔记 代码 地

    java版中国象棋源码-learning:学习笔记

    Ruby, Algorithms, and so on in a few days or hours. The Amazon advanced search for [ and found 512 such books. Of the top ten, nine are programming books (the other is about bookkeeping). Similar ...

    rxswift-to-combine-cheatsheet:RxSwift到Apple的合并备忘单

    笔记 任何观察者 任何订阅者 行为继电器 :cross_mark: 围绕BehaviorSubject的简单包装,可以在Combine中轻松地重新创建 行为主体 CurrentValueSubject 这似乎是隐藏@State的类型 可完成的 :cross_mark: 复合一...

    zellytozelly

    在“zellytozelly-main”这个文件名中,如果没有更多的上下文信息,我们可以假设它可能是一个项目的主分支或者主要代码仓库,包含着开发者的学习笔记、代码示例或实际项目的源代码。 总之,“zellytozelly”项目...

    BackendRoadmap

    1. **基础语言和框架**:后端开发通常始于学习一种或多种编程语言,如Python、Java、Ruby或Node.js。每种语言都有其特性和用途,例如Python适合数据分析和快速开发,而Java则因其跨平台能力和企业级应用而流行。 2....

    xjl_fullstack:前端 全栈学习

    "xjl_fullstack:前端 全栈学习" 的标题和描述表明这是一个关于前端和全栈开发的学习资源,可能是某个教程、笔记或者代码仓库。尽管没有提供具体的压缩包内容,我们可以根据标签"HTML"以及文件名"xjl_fullstack-main...

Global site tag (gtag.js) - Google Analytics