05. Класове, именовани пространства и наследяване

05. Класове, именовани пространства и наследяване

05. Класове, именовани пространства и наследяване

24 октомври 2012

Днес

Наследяване

Наследяването в Ruby става така:

class Person
  def name() 'The Doctor' end
end

class PolitePerson < Person
  def introduction
    "Hi, I am #{name}"
  end
end

PolitePerson.new.introduction # "Hi, I am The Doctor"

Наследяване

ограничения

private методи

Имате достъп до private методите:

class Person
  private
  def name() 'The Doctor' end
end

class PolitePerson < Person
  def introduction() "Hi, I am #{name}" end
end

PolitePerson.new.introduction # "Hi, I am The Doctor"

Наследяване

#is_a? и #instance_of?

class Base; end
class SpaceStation < Base; end

base    = Base.new
station = SpaceStation.new

base.is_a? Base            # true
station.is_a? SpaceStation # true
station.is_a? Base         # true

base.instance_of? Base            # true
station.instance_of? SpaceStation # true
station.instance_of? Base         # false

Наследяване

#is_a? и #instance_of? (3)

#is_a? има синоним #kind_of?

class Base; end
class SpaceStation < Base; end

base    = Base.new
station = SpaceStation.new

base.kind_of? Base            # true
station.kind_of? SpaceStation # true
station.kind_of? Base         # true

Наследяване

#is_a? и #instance_of? (3)

super

Може да предефинирате метод и да извикате родителския със super

class Person
  def introduction_to(other)
    "Hello #{other}."
  end
end

class PolitePerson < Person
  def introduction_to(other)
    super("Mr. #{other}") + " How do you do?"
  end
end

queen = PolitePerson.new
queen.introduction_to('Smith') # "Hello Mr. Smith. How do you do?"

super (2)

Ако извикате super без скоби родителския метод получава същите аргументи.

class Person
  def introduction_to(other)
    "Hello #{other}."
  end
end

class PolitePerson < Person
  def introduction_to(other)
    super + " How do you do?"
  end
end

queen = PolitePerson.new
queen.introduction_to('Smith') # "Hello Smith. How do you do?"

super (3)

super и super() са различни:

class Person
  def introduction_to(other)
    "Hello #{other}."
  end
end

class PolitePerson < Person
  def introduction_to(other)
    super() + " How do you do?"
  end
end

queen = PolitePerson.new
queen.introduction_to('Smith') # error: ArgumentError

Ancestor chain

Ancestor chain (2)

module Foo; end
module Bar; end
module Qux; end

class Base
  include Foo
end

class Derived < Base
  include Bar
  include Qux
end

Derived.ancestors # [Derived, Qux, Bar, Base, Foo, Object, Kernel, BasicObject]

Ancestor chain (3)

модули, миксирани в други модули

module Foo; end
module Bar; end

module Qux
  include Foo
  include Bar
end

class Thing
  include Qux
end

Thing.ancestors # [Thing, Qux, Bar, Foo, Object, Kernel, BasicObject]

Ancestor chain (4)

Има само една версия на метода:

module Talking
  def greeting() "Hello, #{name}" end
end

class Base
  include Talking
  def name()        'Base'   end
  def say_hi_base() greeting end
end

class Derived < Base
  include Talking
  def name()           'Derived' end
  def say_hi_derived() greeting  end
end

derived = Derived.new
derived.say_hi_base    # "Hello, Derived"
derived.say_hi_derived # "Hello, Derived"

methodfinder

$ gem install methodfinder

Полезен gem:

Основните класове в Ruby

protected

Само обекти от същия клас могат да викат protected методи

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

  def +(other)
    Vector.new(*coords.zip(other.coords).map { |a, b| a + b })
  end

  protected
  def coords() [@x, @y] end
end

vector = Vector.new(1, 2) + Vector.new(3, 4)
vector        # Vector.new(4, 6)
vector.coords # error: NoMethodError

private и protected

още известни като Private Public и General Specific

Именовани пространства

Класовете и модулите могат да служат като именовани пространства.

module Useless
  class Thing
  end
end

class Grandfather
  class StraightRazor
  end
end

Useless::Thing.new             # #<Useless::Thing:0x9fc48fc>
Grandfather::StraightRazor.new # #<Grandfather::StraightRazor:0x9fc4744>

Именовани пространства (2)

Ако се намирате в модул, няма нужда да квалицирате константите:

module Useless
  class Thing
  end

  Thing.new         # #<Useless::Thing:0x90950ac>
end

Useless::Thing.new  # #<Useless::Thing:0x909ef6c>
Thing.new           # error: NameError

Търсене на променливи в Ruby

bacon = 2

def foo
  chunky = 10

  1.times do
    chunky       # 10
    chunky = 44
  end

  chunky         # 44
  bacon          # error: NameError
end

foo()

Правила за търсене на константи

Малък пример

PLACE = 'root'
module Outer
  PLACE = 'intermediate'
  module Inner
    PLACE = 'deep'
  end
end

PLACE               # "root"
Outer::Inner::PLACE # "deep"
module Outer
  module Inner
    PLACE           # "deep"
    ::PLACE         # "root"
  end
  PLACE             # "intermediate"
  Inner::PLACE      # "deep"
end

Класови методи

Може да дефинирате класови методи така:

class Something
  def Something.answer
    42
  end
end

Something.answer   # 42

Класови методи (2)

Не може да ги неквалифицирано викате от инстанцията:

class Something
  def Something.answer
    42
  end

  def do_stuff
    answer             # error: NameError
    Something.answer   # 42
  end
end

thing = Something.new
thing.answer           # error: NoMethodError
Something.answer       # 42

thing.do_stuff

Класови методи (3)

Са достъпни в наследниците

class Base
  def Base.answer() 42 end
end

class Derived < Base
  def Derived.say_answer
    answer         # 42
    Base.answer    # 42
  end
end

Derived.answer     # 42
Base.answer        # 42

Derived.say_answer

Класови методи (4)

Въпроси