Учебники

Рубин — Объектно-ориентированный

Ruby — это чисто объектно-ориентированный язык, и все кажется Ruby объектом. Каждое значение в Ruby — это объект, даже самые примитивные вещи: строки, числа и даже true и false. Даже сам класс является объектом, который является экземпляром класса Class . В этой главе вы познакомитесь со всеми основными функциями, связанными с объектно-ориентированным рубином.

Класс используется для указания формы объекта, и он объединяет представление данных и методы для манипулирования этими данными в одном аккуратном пакете. Данные и методы в классе называются членами класса.

Определение класса Ruby

Когда вы определяете класс, вы определяете план для типа данных. На самом деле это не определяет какие-либо данные, но определяет, что означает имя класса, то есть, из чего будет состоять объект класса и какие операции могут быть выполнены с таким объектом.

Определение класса начинается с ключевого слова class, за которым следует имя класса, и заканчивается разделением. Например, мы определили класс Box, используя ключевое слово class следующим образом:

class Box
   code
end

Имя должно начинаться с заглавной буквы, и по соглашению имена, содержащие более одного слова, запускаются вместе с каждым словом, написанным с заглавной буквы, и без разделительных символов (CamelCase).

Определить объекты Ruby

Класс предоставляет чертежи для объектов, поэтому в основном объект создается из класса. Мы объявляем объекты класса, используя ключевое слово new . Следующие операторы объявляют два объекта класса Box —

box1 = Box.new
box2 = Box.new

Метод инициализации

Метод initialize является стандартным методом класса Ruby и работает почти так же, как конструктор в других объектно-ориентированных языках программирования. Метод initialize полезен, когда вы хотите инициализировать некоторые переменные класса во время создания объекта. Этот метод может принимать список параметров и, как и любой другой метод ruby, ему предшествует ключевое слово def, как показано ниже —

class Box
   def initialize(w,h)
      @width, @height = w, h
   end
end

Переменные экземпляра

Переменные экземпляра являются своего рода атрибутами класса и становятся свойствами объектов после создания объектов с использованием класса. Атрибуты каждого объекта назначаются индивидуально и не имеют общего значения с другими объектами. Доступ к ним осуществляется с помощью оператора @ внутри класса, но для доступа к ним вне класса мы используем открытые методы, которые называются методами доступа . Если мы возьмем определенный выше класс Box, то @width и @height являются переменными экземпляра для класса Box.

class Box
   def initialize(w,h)
      # assign instance variables
      @width, @height = w, h
   end
end

Методы доступа и установки

Чтобы сделать переменные доступными извне класса, они должны быть определены в методах доступа , эти методы доступа также известны как методы получения. В следующем примере показано использование методов доступа —

Live Demo

#!/usr/bin/ruby -w

# define a class
class Box
   # constructor method
   def initialize(w,h)
      @width, @height = w, h
   end

   # accessor methods
   def printWidth
      @width
   end

   def printHeight
      @height
   end
end

# create an object
box = Box.new(10, 20)

# use accessor methods
x = box.printWidth()
y = box.printHeight()

puts "Width of the box is : #{x}"
puts "Height of the box is : #{y}"

Когда приведенный выше код выполняется, он дает следующий результат —

Width of the box is : 10
Height of the box is : 20

Подобно методам доступа, которые используются для доступа к значению переменных, Ruby предоставляет способ установки значений этих переменных извне класса с помощью методов установки , которые определены ниже:

Live Demo

#!/usr/bin/ruby -w

# define a class
class Box
   # constructor method
   def initialize(w,h)
      @width, @height = w, h
   end

   # accessor methods
   def getWidth
      @width
   end
   def getHeight
      @height
   end

   # setter methods
   def setWidth=(value)
      @width = value
   end
   def setHeight=(value)
      @height = value
   end
end

# create an object
box = Box.new(10, 20)

# use setter methods
box.setWidth = 30
box.setHeight = 50

# use accessor methods
x = box.getWidth()
y = box.getHeight()

puts "Width of the box is : #{x}"
puts "Height of the box is : #{y}"

Когда приведенный выше код выполняется, он дает следующий результат —

Width of the box is : 30
Height of the box is : 50

Методы экземпляра

Методы экземпляра также определяются так же, как мы определяем любой другой метод с использованием ключевого слова def, и их можно использовать только с использованием экземпляра класса, как показано ниже. Их функциональные возможности не ограничены доступом к переменным экземпляра, но они также могут сделать намного больше в соответствии с вашими требованиями.

Live Demo

#!/usr/bin/ruby -w

# define a class
class Box
   # constructor method
   def initialize(w,h)
      @width, @height = w, h
   end
   # instance method
   def getArea
      @width * @height
   end
end

# create an object
box = Box.new(10, 20)

# call instance methods
a = box.getArea()
puts "Area of the box is : #{a}"

Когда приведенный выше код выполняется, он дает следующий результат —

Area of the box is : 200

Класс Методы и Переменные

Переменные класса — это переменная, которая используется всеми экземплярами класса. Другими словами, существует один экземпляр переменной, и к ней обращаются экземпляры объекта. Переменные класса начинаются с двух символов @ (@@). Переменная класса должна быть инициализирована в определении класса, как показано ниже.

Метод класса определяется с помощью def self.methodname () , который заканчивается конечным разделителем и вызывается с использованием имени класса в качестве classname.methodname, как показано в следующем примере.

#!/usr/bin/ruby -w

class Box
   # Initialize our class variables
   @@count = 0
   def initialize(w,h)
      # assign instance avriables
      @width, @height = w, h

      @@count += 1
   end

   def self.printCount()
      puts "Box count is : #@@count"
   end
end

# create two object
box1 = Box.new(10, 20)
box2 = Box.new(30, 100)

# call class method to print box count
Box.printCount()

Когда приведенный выше код выполняется, он дает следующий результат —

Box count is : 2

Метод to_s

Любой класс, который вы определяете, должен иметь метод экземпляра to_s для возврата строкового представления объекта. Ниже приведен простой пример представления объекта Box с точки зрения ширины и высоты.

Live Demo

#!/usr/bin/ruby -w

class Box
   # constructor method
   def initialize(w,h)
      @width, @height = w, h
   end
   # define to_s method
   def to_s
      "(w:#@width,h:#@height)"  # string formatting of the object.
   end
end

# create an object
box = Box.new(10, 20)

# to_s method will be called in reference of string automatically.
puts "String representation of box is : #{box}"

Когда приведенный выше код выполняется, он дает следующий результат —

String representation of box is : (w:10,h:20)

Контроль доступа

Ruby предоставляет вам три уровня защиты на уровне методов экземпляра, который может быть открытым, закрытым или защищенным . Ruby не применяет никакого контроля доступа к переменным экземпляра и класса.

  • Публичные методы — Публичные методы могут быть вызваны кем угодно. Методы общедоступны по умолчанию, за исключением инициализации, которая всегда является закрытой.

  • Частные методы — к закрытым методам нельзя получить доступ или даже посмотреть извне класса. Только методы класса могут получить доступ к закрытым членам.

  • Защищенные методы . Защищенный метод может вызываться только объектами определяющего класса и его подклассов. Доступ хранится в семье.

Публичные методы — Публичные методы могут быть вызваны кем угодно. Методы общедоступны по умолчанию, за исключением инициализации, которая всегда является закрытой.

Частные методы — к закрытым методам нельзя получить доступ или даже посмотреть извне класса. Только методы класса могут получить доступ к закрытым членам.

Защищенные методы . Защищенный метод может вызываться только объектами определяющего класса и его подклассов. Доступ хранится в семье.

Ниже приведен простой пример, демонстрирующий синтаксис всех трех модификаторов доступа:

Live Demo

#!/usr/bin/ruby -w

# define a class
class Box
   # constructor method
   def initialize(w,h)
      @width, @height = w, h
   end

   # instance method by default it is public
   def getArea
      getWidth() * getHeight
   end

   # define private accessor methods
   def getWidth
      @width
   end
   def getHeight
      @height
   end
   # make them private
   private :getWidth, :getHeight

   # instance method to print area
   def printArea
      @area = getWidth() * getHeight
      puts "Big box area is : #@area"
   end
   # make it protected
   protected :printArea
end

# create an object
box = Box.new(10, 20)

# call instance methods
a = box.getArea()
puts "Area of the box is : #{a}"

# try to call protected or methods
box.printArea()

Когда приведенный выше код выполняется, он дает следующий результат. Здесь первый метод вызывается успешно, но второй метод вызвал проблему.

Area of the box is : 200
test.rb:42: protected method `printArea' called for #
<Box:0xb7f11280 @height = 20, @width = 10> (NoMethodError)

Наследование классов

Одним из наиболее важных понятий в объектно-ориентированном программировании является наследование. Наследование позволяет нам определять класс в терминах другого класса, что облегчает создание и поддержку приложения.

Наследование также дает возможность повторно использовать функциональность кода и быстрое время реализации, но, к сожалению, Ruby не поддерживает множественные уровни наследования, но Ruby поддерживает миксины . Миксин подобен специализированной реализации множественного наследования, в которой наследуется только часть интерфейса.

При создании класса, вместо того, чтобы писать совершенно новые члены-данные и функции-члены, программист может указать, что новый класс должен наследовать члены существующего класса. Этот существующий класс называется базовым классом или суперклассом , а новый класс называется производным классом или подклассом .

Ruby также поддерживает концепцию подклассов, т. Е. Наследование, и следующий пример объясняет эту концепцию. Синтаксис для расширения класса прост. Просто добавьте символ <и имя суперкласса в оператор класса. Например, следующие определяют класс BigBox как подкласс Box

Live Demo

#!/usr/bin/ruby -w

# define a class
class Box
   # constructor method
   def initialize(w,h)
      @width, @height = w, h
   end
   # instance method
   def getArea
      @width * @height
   end
end

# define a subclass
class BigBox < Box

   # add a new instance method
   def printArea
      @area = @width * @height
      puts "Big box area is : #@area"
   end
end

# create an object
box = BigBox.new(10, 20)

# print the area
box.printArea()

Когда приведенный выше код выполняется, он дает следующий результат —

Big box area is : 200

Переопределение методов

Хотя вы можете добавить новую функциональность в производный класс, но иногда вы хотели бы изменить поведение уже определенного метода в родительском классе. Вы можете сделать это, просто сохранив имя метода и переопределив функциональность метода, как показано ниже в примере:

Live Demo

#!/usr/bin/ruby -w

# define a class
class Box
   # constructor method
   def initialize(w,h)
      @width, @height = w, h
   end
   # instance method
   def getArea
      @width * @height
   end
end

# define a subclass
class BigBox < Box

   # change existing getArea method as follows
   def getArea
      @area = @width * @height
      puts "Big box area is : #@area"
   end
end

# create an object
box = BigBox.new(10, 20)

# print the area using overriden method.
box.getArea()

Перегрузка оператора

Мы бы хотели, чтобы оператор + выполнял векторное сложение двух объектов Box, используя +, оператор * для умножения ширины и высоты Box на скаляр и оператор unary — для отрицания ширины и высоты Box. Вот версия класса Box с определенными математическими операторами:

class Box
   def initialize(w,h)     # Initialize the width and height
      @width,@height = w, h
   end

   def +(other)       # Define + to do vector addition
      Box.new(@width + other.width, @height + other.height)
   end

   def -@           # Define unary minus to negate width and height
      Box.new(-@width, -@height)
   end

   def *(scalar)           # To perform scalar multiplication
      Box.new(@width*scalar, @height*scalar)
   end
end

Замораживание объектов

Иногда мы хотим предотвратить изменение объекта. Метод freeze в Object позволяет нам делать это, эффективно превращая объект в константу. Любой объект можно заморозить, вызвав Object.freeze . Замороженный объект не может быть изменен: вы не можете изменить его переменные экземпляра.

Вы можете проверить, заморожен ли данный объект или нет, используя Object.frozen? метод, который возвращает true в случае, если объект заморожен, иначе возвращается ложное значение. Следующий пример проясняет концепцию —

Live Demo

#!/usr/bin/ruby -w

# define a class
class Box
   # constructor method
   def initialize(w,h)
      @width, @height = w, h
   end

   # accessor methods
   def getWidth
      @width
   end
   def getHeight
      @height
   end

   # setter methods
   def setWidth=(value)
      @width = value
   end
   def setHeight=(value)
      @height = value
   end
end

# create an object
box = Box.new(10, 20)

# let us freez this object
box.freeze
if( box.frozen? )
   puts "Box object is frozen object"
else
   puts "Box object is normal object"
end

# now try using setter methods
box.setWidth = 30
box.setHeight = 50

# use accessor methods
x = box.getWidth()
y = box.getHeight()

puts "Width of the box is : #{x}"
puts "Height of the box is : #{y}"

Когда приведенный выше код выполняется, он дает следующий результат —

Box object is frozen object
test.rb:20:in `setWidth=': can't modify frozen object (TypeError)
   from test.rb:39

Константы класса

Вы можете определить константу внутри класса, присвоив переменной числовое или строковое значение, которое определяется без использования @ или @@. По соглашению мы сохраняем имена констант в верхнем регистре.

Как только константа определена, вы не можете изменить ее значение, но вы можете получить доступ к константе непосредственно внутри класса, как переменная, но если вы хотите получить доступ к константе вне класса, вам придется использовать classname :: constant, как показано в Пример ниже.

Live Demo

#!/usr/bin/ruby -w

# define a class
class Box
   BOX_COMPANY = "TATA Inc"
   BOXWEIGHT = 10
   # constructor method
   def initialize(w,h)
      @width, @height = w, h
   end
   # instance method
   def getArea
      @width * @height
   end
end

# create an object
box = Box.new(10, 20)

# call instance methods
a = box.getArea()
puts "Area of the box is : #{a}"
puts Box::BOX_COMPANY
puts "Box weight is: #{Box::BOXWEIGHT}"

Когда приведенный выше код выполняется, он дает следующий результат —

Area of the box is : 200
TATA Inc
Box weight is: 10

Константы класса наследуются и могут быть переопределены как методы экземпляра.

Создать объект с помощью Allocate

Может возникнуть ситуация, когда вы хотите создать объект, не вызывая его конструктор initialize, т.е. используя новый метод, в таком случае вы можете вызвать allocate , который создаст для вас неинициализированный объект, как в следующем примере:

Live Demo

#!/usr/bin/ruby -w

# define a class
class Box
   attr_accessor :width, :height

   # constructor method
   def initialize(w,h)
      @width, @height = w, h
   end

   # instance method
   def getArea
      @width * @height
   end
end

# create an object using new
box1 = Box.new(10, 20)

# create another object using allocate
box2 = Box.allocate

# call instance method using box1
a = box1.getArea()
puts "Area of the box is : #{a}"

# call instance method using box2
a = box2.getArea()
puts "Area of the box is : #{a}"

Когда приведенный выше код выполняется, он дает следующий результат —

Area of the box is : 200
test.rb:14: warning: instance variable @width not initialized
test.rb:14: warning: instance variable @height not initialized
test.rb:14:in `getArea': undefined method `*' 
   for nil:NilClass (NoMethodError) from test.rb:29

Информация о классе

Если определения классов являются исполняемым кодом, это означает, что они выполняются в контексте некоторого объекта: self должно ссылаться на что-то. Давайте выясним, что это.

#!/usr/bin/ruby -w

class Box
   # print class information
   puts "Type of self = #{self.type}"
   puts "Name of self = #{self.name}"
end

Когда приведенный выше код выполняется, он дает следующий результат —

Type of self = Class
Name of self = Box

Это означает, что определение класса выполняется с этим классом в качестве текущего объекта. Это означает, что методы в метаклассе и его суперклассах будут доступны во время выполнения определения метода.