Chapter 3: Classes, Objects and Variables

class BookInStock
  def initialize(isbn, price)
    @isbn = isbn
    @price = Float(price)
  end
end
a_book = BookInStock.new
another_book = BookInStock.new

initialize method is a special method in Ruby programs. When you call BookInStock.new to create a new object, Ruby allocates some memory to hold an uninitialized object and then calls that object's initialize method, passing in any parameters that were passed to new.

puts method simply writes strings to your program's standard output. When you pass it an object based on a class you wrote, it doesn't really know what to do with it, so it uses a very simple expedient: it writes the name of the object's class, followed by a colon and the object's unique identifier (a hexadecimal number). It puts the whole lot inside #<...>.

一、Objects and Attributes

1.Ruby provides a convenient shortcut. attr_reader creates these attribute reader methods for you:

class BookInStock
  attr_reader :isbn, :price
  def initialize(isbn, price)
    @isbn = isbn
    @price = Float(price)
  end
  # ..
end
book= BookInStock.new("isbn1", 12.34)
puts "ISBN =#{book.isbn}"
puts "Price =#{book.price}"
produces:
ISBN = isbn1
Price = 12.34

This is the first time we've used symbols in this chapter.symbols are just a convenient way of referencing a name.
    (1). Writable Attributes

class BookInStock
  attr_reader :isbn, :price
  def initialize(isbn, price)
    @isbn = isbn
    @price = Float(price)
  end
  def price=(new_price)
    @price = new_price
  end
  # ...
end
book = BookInStock.new("isbn1", 33.80)
puts "ISBN =#{book.isbn}"
puts "Price =#{book.price}"
book.price = book.price * 0.75 # discount price
puts "New price =#{book.price}"

produces:
ISBN = isbn1
Price = 33.8
New price = 25.349999999999998
    If you create a method whose name ends  with an equals sign, that name can appear on the left side of an assignment.

    Ruby provides a shortcut for creating these simple attribute-setting methods. If you want a write-only accessor, you can use the form attr_writer, but that's fairly rare.
    You're far more likely to want both a reader and a writer for a given attribute, so you'll use the handydandy attr_accessor method:

class BookInStock
  attr_reader :isbn
  attr_accessor :price
  def initialize(isbn, price)
    @isbn = isbn
    @price = Float(price)
  end
  # ...
end
book = BookInStock.new("isbn1", 33.80)
puts "ISBN =#{book.isbn}"
puts "Price =#{book.price}"
book.price = book.price * 0.75 # discount price
puts "New price =#{book.price}"

produces:
ISBN = isbn1
Price = 33.8
New price = 25.349999999999998
    (2)Virtual Attributes 虚拟属性 => [Continued]
class BookInStock
  attr_reader :isbn
  attr_accessor :price
  def initialize(isbn, price)
    @isbn = isbn
    @price = Float(price)
  end
  def price_in_cents
    Integer(price*100 + 0.5)
  end
  def price_in_cents=(cents)
    @price = cents / 100.0
  end
  # ...
end
book = BookInStock.new("isbn1", 33.80)
puts "Price = #{book.price}"
puts "Price in cents = #{book.price_in_cents}"
book.price_in_cents = 1234
puts "Price =#{book.price}"
puts "Price in cents =#{book.price_in_cents}"
produces:
Price = 33.8
Price in cents = 3380
Price = 12.34
Price in cents = 1234
    (3)Attributes, Instance Variables, and Methods

    When you design a class, you decide what internal state it has and also decide how that state is to appear on the outside (to users of your class). The internal state is held in instance variables. 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.

2.Classes Working with Other Classes

book_in_stock.rb

class BookInStock
  attr_reader :isbn, :price
  def initialize(isbn, price)
    @isbn = isbn
    @price = Float(price)
  end
end
csv_reader.rb
require 'csv' 
require_relative 'book_in_stock'

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  
  def total_value_in_stock   # later we'll see how to use inject to sum a collection
    sum = 0.0        
    @books_in_stock.each {|book| sum += book.price}
    sum
  end  
  
  def number_of_each_isbn
    # ...
  end
end
stock_stats.rb
require_relative 'csv_reader'

reader = CsvReader.new

ARGV.each do |csv_file_name|
  STDERR.puts "Processing #{csv_file_name}"
  reader.read_in_csv_data(csv_file_name)
end

puts "Total value = #{reader.total_value_in_stock}"

 It uses the ARGV variable to access the program's command-line arguments, loading CSV data for each file specified on the command line.


3.Access Control

The good news is that the only easy way to change an object's state in Ruby is by calling one of its methods.
Control access to the methods, and you've controlled access to the object.

Ruby gives you three levels of protection:

Public methods can be called by anyone—no access control is enforced. Methods are public by default (except for initialize, which is always private).
Protected methods can be invoked only by objects of the defining class and its subclasses. Access is kept within the family.
Private methods cannot be called with an explicit receiver

This means that private methods can be called only in the context of the current object; you can't invoke another object's private methods.
If a method is protected, it may be called by any instance of the defining class or its subclasses.
If a method is private, it may be called only within the context of the calling object—it is never possible to access another object's private methods directly, even if the object is of the same class as the caller.

    (1)Specifying Access Control

class MyClass
  def method1 # default is 'public'
    #...
  end
protected # subsequent methods will be 'protected'
  def method2 # will be 'protected'
    #...
  end
private # subsequent methods will be 'private'
  def method3 # will be 'private'
    #...
  end
public # subsequent methods will be 'public'
  def method4 # so this will be 'public'
    #...
  end
end
Alternatively, you can set access levels of named methods by listing them as arguments to the access control functions:
class MyClass
  def method1
  end
  def method2
  end
  # ... and so on
  public :method1, :method4
  protected :method2
  private :method3
end
some examples:
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
savings = Account.new(100)
checking = Account.new(200)
trans = Transaction.new(checking, savings)
trans.transfer(50)
4.Variables

Variables are used to keep track of objects; each variable holds a reference to an object.

So, is a variable an object? In Ruby, the answer is "no". A variable is simply a reference to an object

Objects float around in a big pool somewhere (the heap, most of the time) and are pointed to by variables.

you could avoid aliasing by using the dup method of String, which creates a new string object with identical contents.

You can also prevent anyone from changing a particular object by freezing it. Attempt to alter a frozen object, and Ruby will raise a Runtime Error exception:

person1 ="Tim"
person2 = person1
person1.freeze # prevent modifications to the object
person2[0] ="J"
produces:
from prog.rb:4:in `<main>'
prog.rb:4:in `[]=': can't modify frozen String (RuntimeError)
for now, know that everything you manipulate in Ruby is an object and that objects start life as instances of classes. And one of the most common things we do with objects is create collections of them.

转载于:https://my.oschina.net/jeekwong/blog/261732

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值