03. Въведение в обектно-ориентирано Ruby

03. Въведение в обектно-ориентирано Ruby

03. Въведение в обектно-ориентирано Ruby

18 октомври 2011

Днес

Сайт на курса

Първа задача

Тривиа!

Където аз задавам въпроси!

Въпрос 1

Какво ще направи следният код?

things = [:bacon, :cheese, :tea]

p things[1]
p things[10]

things[4] = :snickers
p things

Ще отпечата :cheеse, nil и [:bacon, :cheеse, :tea, nil, :snickers].

Въпрос 2

Кое е подходящо за ключ в хеш?

immutable обекти, които могат да се хешират.

Въпрос 3

Какво ще изведе следният код:

words = %w[foo bar baz]
names = words
names[0] << 'l'
names[1] = 'qux'
words[2] = 'larodi'

puts words

%w[fool qux larodi]

Въпрос 4

Какви са методите, които завършват на ? или !

#foo? е предикат, #foo! е по-деструктивна версия на #foo

Въпрос 5

Каква е разликата между Proc и lambda? Каква им е връзката с yield?

Дълго :)

Ruby и ООП

Класове

прост пример

Дефинират се с class. Методите, дефинирани в тялото на класа, стават методи на инстанциите му. Инстанцират се се с ИмеНаКласа.new.

class Bacon
  def chunky?
    'yes, of course!'
  end
end

bacon = Bacon.new
bacon.chunky?      # "yes, of course!"

Класове

полета

Полетата (още: instance variables) имат представка @.

class Vector
  def initialize(x, y)
    @x = x
    @y = y
  end

  def length
    (@x * @x + @y * @y) ** 0.5
  end
end

vector = Vector.new 2.0, 3.0
vector.length()     # 3.605551275463989
vector.length       # 3.605551275463989

Класове

полета (2)

По подразбиране имат стойност nil.

class Person
  def heh
    @something
  end
end

person = Person.new
person.heh      # nil

Класове

викане на методи

В метод на може да извикате друг със self.име_на_метод или просто име_на_метод:

class Person
  def initialize(name) @name = name                end
  def say_hi()         puts "My name is #{@name}!" end
  def sound_smart()    puts "1101000 1101001"      end

  def talk
    self.say_hi
    sound_smart
  end
end

mel = Person.new 'Mel'
mel.talk

Такова подравняване на методи е гадно, но пък се събира в слайд

Класове

self

В методите на класа, self е референция към обекта, на който е извикан методът. Като this в Java.

class Person
  def me
    self
  end
end

person = Person.new
person           # #<Person:0x9678000>
person.me        # #<Person:0x9678000>
person.me.me     # #<Person:0x9678000>

Атрибути

Полетата не са публично достъпни. Може да ги достигнете само чрез метод.

class Person
  def initialize(age)
    @age = age
  end

  def age
    @age
  end

  def set_age(age)
    @age = age
  end
end

person = Person.new(33)
person.age          # 33
person.set_age 20
person.age          # 20

Атрибути

setter-и

Разбира се, set_age е гадно име на метод. Може и по-добре:

class Person
  def age
    @age
  end

  def age=(value)
    @age = value
  end
end

person = Person.new
person.age = 33  # Същото като person.age=(33)

person.age       # 33

Атрибути

attr_accessor

Последното е досадно за писане. Затова:

class Person
  attr_accessor :age
end

person = Person.new
person.age = 33

person.age # 33

Атрибути

другите макроси

Ако ви трябва само getter или setter, може така:

class Person
  attr_reader :name
  attr_writer :grade
  attr_accessor :age, :height
end

Атрибути

какво е attr_accessor?

attr_accessor е метод, който генерира два метода — #foo и #foo=. Достъпен е в дефинициите на класове. Неформален термин за такива методи е "class macro".

Има ги в изобилие.

Атрибути

Meyer's Uniform Access Principle

Обърнете внимание, че следните два реда правят едно и също:

person.age()
person.age

Няма разлика между достъпване на атрибут и извикване на метод, който го изчислява. Това се нарича Uniform Access Principle и като цяло е хубаво нещо.

Конвенции

В Ruby важат следните конвенции.

"Отваряне" на класове

Във всеки момент може да "отворите" клас и да му добавите методи.

class Person
  def name
    'River'
  end
end

class Person
  def say_hi
    "Hi, I am #{name}."
  end
end

Person.new.say_hi # "Hi, I am River."
Person.new.name   # "River"

Повторно дефиниране на метод

Ако дефинирате един метод два пъти, втората дефиниция измества първата.

class Something
  def name
    'Tom Baker'
  end

  def name
    'Colin Baker'
  end
end

Something.new.name # => 'Colin Baker'

alias

Въпреки името си, alias прави копие на метод.

class Array
  alias old_inject inject

  def inject(*args, &block)
    puts "I see you are using #inject. Let me help!"
    old_inject(*args, &block) * 0.01
  end
end

[1, 2, 3, 4, 5, 6].inject { |a, b| a + b } # 0.21

Object#methods

Ако викнете #methods на нещо, ще получите масив от символи с имената на методите му.

Помните ли Array#-?

class Person
  def foo() end
  def bar() end
end

Person.new.methods - Object.new.methods # [:foo, :bar]

Предефиниране на оператори

Много интуитивно.

class Vector
  attr_accessor :x, :y

  def initialize(x, y)
    @x, @y = x, y
  end

  def +(other)
    Vector.new(x + other.x, y + other.y)
  end

  def inspect
    "Vector.new(#@x, #@y)"
  end
end

Vector.new(1, 5) + Vector.new(3, 10) # Vector.new(4, 15)

private

class Person
  def say_hi
    "Hello! I am #{name}"
  end

  private

  def name
    'the Doctor'
  end
end

person = Person.new
person.say_hi     # "Hello! I am the Doctor"
person.name       # error: NoMethodError

private (2)

Ако един метод е private, не може да го викате с явен получател. Дори със self.

class Person
  def say_hi
    "Hello! I am #{self.name}"
  end

  private

  def name
    'the Doctor'
  end
end

person = Person.new
person.say_hi     # error: NoMethodError

Въпроси