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编程语言中对象、类与属性的概念,通过一个二手书店的案例,展示了如何使用Ruby来管理和操作数据。文章详细解释了类的初始化、属性的定义与访问,并介绍了Ruby中对属性的多种管理方式,如`attr_reader`、`attr_accessor`等。同时,文章还讨论了Ruby的访问控制机制,包括公共、受保护和私有级别,以及如何在类中实现转账功能的例子。此外,文章还涉及了变量在Ruby中的特性,强调了变量与对象的区别,以及如何使用`dup`和`freeze`来复制和防止对象被修改。
2万+

被折叠的 条评论
为什么被折叠?



