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
Методы доступа и установки
Чтобы сделать переменные доступными извне класса, они должны быть определены в методах доступа , эти методы доступа также известны как методы получения. В следующем примере показано использование методов доступа —
#!/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 предоставляет способ установки значений этих переменных извне класса с помощью методов установки , которые определены ниже:
#!/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, и их можно использовать только с использованием экземпляра класса, как показано ниже. Их функциональные возможности не ограничены доступом к переменным экземпляра, но они также могут сделать намного больше в соответствии с вашими требованиями.
#!/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 с точки зрения ширины и высоты.
#!/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 не применяет никакого контроля доступа к переменным экземпляра и класса.
-
Публичные методы — Публичные методы могут быть вызваны кем угодно. Методы общедоступны по умолчанию, за исключением инициализации, которая всегда является закрытой.
-
Частные методы — к закрытым методам нельзя получить доступ или даже посмотреть извне класса. Только методы класса могут получить доступ к закрытым членам.
-
Защищенные методы . Защищенный метод может вызываться только объектами определяющего класса и его подклассов. Доступ хранится в семье.
Публичные методы — Публичные методы могут быть вызваны кем угодно. Методы общедоступны по умолчанию, за исключением инициализации, которая всегда является закрытой.
Частные методы — к закрытым методам нельзя получить доступ или даже посмотреть извне класса. Только методы класса могут получить доступ к закрытым членам.
Защищенные методы . Защищенный метод может вызываться только объектами определяющего класса и его подклассов. Доступ хранится в семье.
Ниже приведен простой пример, демонстрирующий синтаксис всех трех модификаторов доступа:
#!/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 —
#!/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
Переопределение методов
Хотя вы можете добавить новую функциональность в производный класс, но иногда вы хотели бы изменить поведение уже определенного метода в родительском классе. Вы можете сделать это, просто сохранив имя метода и переопределив функциональность метода, как показано ниже в примере:
#!/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 в случае, если объект заморожен, иначе возвращается ложное значение. Следующий пример проясняет концепцию —
#!/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, как показано в Пример ниже.
#!/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 , который создаст для вас неинициализированный объект, как в следующем примере:
#!/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
Это означает, что определение класса выполняется с этим классом в качестве текущего объекта. Это означает, что методы в метаклассе и его суперклассах будут доступны во время выполнения определения метода.