Введение в объектно-ориентированное программирование с Ruby

1656659772 vvedenie v obektno orientirovannoe programmirovanie s ruby

от Нишанта Мишры

4NdyCePiNGyAAsSOl3bwYWdN20pXjqCSqpz-

Будучи студентом информатики, я провожу много времени, изучая новые языки и играя с ними. Каждый новый язык может предложить нечто уникальное. Ввиду этого большинство начинающих начинают свой путь программирования с процедурных языков, таких как C, или с объектно-ориентированных языков, таких как JavaScript и C++.

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

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

Знакомство с объектно-ориентированной парадигмой (ООП)

В ООП мы определяем вещи, которые обрабатывает наша программа. Как люди, мы думаем о вещах как объектах с атрибутами и поведением, и мы взаимодействуем с вещами на основе этих атрибутов и поведения. Вещью могут быть машина, книга и т.д. Такие вещи становятся классами (чертежами объектов), и мы создаем объекты из этих классов.

Каждый экземпляр (объект) содержит переменные экземпляра, являющиеся состоянием объекта (атрибуты). Поведение объектов представлено методами.

Возьмем для примера автомобиль. Автомобиль – это то, что сделало бы его класс. Конкретный тип автомобиля, скажем, BMW есть объект класса Автомобиль. The атрибуты/свойства BMW, например цвет и номер модели, можно хранить в сменных экземплярах. И если вы хотите выполнить операцию с объектом, например вождение, тогда «привод» описывает поведение, определяемое как метод.

Краткий урок синтаксиса

  • Чтобы закончить строку в программе Ruby, точка с запятой (;) необязательна (но обычно не используется)
  • Рекомендуется 2-пробеловое отступление для каждого вложенного уровня (не обязательно, как у Python)
  • Без фигурных скобок {} используются, и конец Ключевое слово используется для обозначения конца блока управления потоком
  • Для комментариев мы используем # символ

Объекты создаются в Ruby путём вызова a новый в классе, как в примере ниже:

class Car  def initialize(name, color)    @name = name    @color = color  end
  def get_info    "Name: #{@name}, and Color: #{@color}"  endend
my_car = Car.new("Fiat", "Red")puts my_car.get_info

Чтобы понять, что происходит в коде выше:

  • У нас есть класс под названием Car двумя способами, initialize и get_info.
  • Сменные экземпляра в Ruby начинаются с @ (Например @name). Интересная часть состоит в том, что переменные поначалу не объявляются. Они возникают при первом использовании, а затем доступны для всех методов экземпляров класса.
  • Вызов new метод вызывает initialize метод вызова. initialize это специальный метод, используемый как конструктор.

Доступ к данным

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

Чтобы получить и изменить данные, нам нужны методы getter и setter соответственно. Давайте рассмотрим эти способы на том же примере автомобиля.

class Car  def initialize(name, color) # "Constructor"    @name = name    @color = color  end
  def color    @color  end
  def color= (new_color)    @color = new_color  endend
my_car = Car.new("Fiat", "Red")puts my_car.color # Red
my_car.color = "White"puts my_car.color # White

В Ruby «getter» и «setter» определены с тем же именем, что и сменная экземпляра, с которой мы имеем дело.

В примере выше, когда мы говорим my_car.colorэто действительно вызывает color метод, который в свою очередь возвращает название цвета.

Примечание. Обратите внимание на то, как Ruby допускает пробел между color и равно знаку при использовании сеттера, даже если название метода color=

Написание этих методов getter/setter позволяет нам иметь больше контроля. Но чаще всего получить имеющееся значение и установить новое значение просто. Следовательно, должен быть более простой способ вместо фактического определения методов получения/настройки.

Более простой способ

Используя attr_* вместо этого мы можем получить существующее значение и установить новое значение.

  • attr_accessor: как для получения, так и для установки
  • attr_reader: только для получателя
  • attr_writer: только для сеттера

Давайте рассмотрим эту форму на том же примере автомобиля.

class Car  attr_accessor :name, :colorend
car1 = Car.newputs car1.name # => nil
car1.name = "Suzuki"car1.color = "Gray"puts car1.color # => Gray
car1.name = "Fiat"puts car1.name # => Fiat

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

Разговор о лучших практиках

В примере выше мы не инициализировали значение для @name и @color переменные экземпляра, не являющиеся хорошей практикой. Кроме того, поскольку переменные экземпляра установлены на ноль, объект car1 не имеет никакого смысла. Всегда полезно устанавливать переменные экземпляра с помощью конструктора, как в примере ниже.

class Car  attr_accessor :name, :color    def initialize(name, color)    @name = name    @color = color  endend
car1 = Car.new("Suzuki", "Gray")puts car1.color # => Gray
car1.name = "Fiat"puts car1.name # => Fiat

Методы класса и переменные класса

Следовательно, способы класса вызываются в классе, а не в экземпляре класса. Это похожи на статический методы в Java

Примечание: self вне определения метода ссылается на объект класса. Переменные класса начинаются с @@

На самом деле существует три способа определения методов класса в Ruby:

Внутри определения класса

  1. Использование ключевого слова self с названием метода:
class MathFunctions  def self.two_times(num)    num * 2  endend
# No instance createdputs MathFunctions.two_times(10) # => 20

2. Использование <<; себя

class MathFunctions  class << self    def two_times(num)      num * 2    end  endend
# No instance createdputs MathFunctions.two_times(10) # =&gt; 20

Вне определения класса

3. Использование имени класса с названием метода

class MathFunctionsend
def MathFunctions.two_times(num)  num * 2end
# No instance createdputs MathFunctions.two_times(10) # =&gt; 20

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

В Ruby каждый класс неявно наследует класс Object. Давайте рассмотрим пример.

class Car  def to_s    "Car"  end
  def speed    "Top speed 100"  endend
class SuperCar < Car  def speed # Override    "Top speed 200"  endend
car = Car.newfast_car = SuperCar.new
puts "#{car}1 #{car.speed}" # =&gt; Car1 Top speed 100puts "#{fast_car}2 #{fast_car.speed}" # => Car2 Top speed 200

В приведенном выше примере SuperCar класс заменяет speed метод, унаследованный от Car класс. Символ &lt; обозначает наследственность.

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

Модули в Ruby

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

Модуль – это контейнер для классов, методов, констант или даже других модулей. Как и класс, модуль не может быть создан, но служит двум основным целям:

Модули как пространство имен

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

module Patterns  class Match    attr_accessor :matched  endend
module Sports  class Match    attr_accessor :score  endend
match1 = Patterns::Match.newmatch1.matched = "true"
match2 = Sports::Match.newmatch2.score = 210

В приведенном выше примере мы имеем два класса с именами Matchмы можем различать их и предотвращать столкновения, просто инкапсулируя их в разные модули.

Модули как Mix-in

В объектно-ориентированной парадигме у нас есть концепция интерфейсов. Mix-in обеспечивает способ обмена кодом между несколькими классами. Кроме того, мы можем также включить такие встроенные модули, как Enumerable и значительно облегчает нашу задачу. Давайте рассмотрим пример.

module PrintName  attr_accessor :name  def print_it    puts "Name: #{@name}"  endend
class Person  include PrintNameend
class Organization  include PrintNameend
person = Person.newperson.name = "Nishant"puts person.print_it # =&gt; Name: Nishant
organization = Organization.neworganization.name = "freeCodeCamp"puts organization.print_it # =&gt; Name: freeCodeCamp 

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

Сфера действия в Ruby

Мы увидим, как область работает для:

Область переменных

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

name = "Nishant"
class MyClass  def my_fun    name = "John"    puts name # =&gt; John  end
puts name # =&gt; Nishant

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

Область применения констант

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

module MyModule  PI = 3.14  class MyClass    def value_of_pi      puts PI # =&gt; 3.14      PI = "3.144444"      puts PI # => 3.144444    end  end  puts PI # =&gt; 3.14end

Область применения блоков

Блоки наследуют внешнюю область. Давайте поймем это на фантастическом примере, который я нашел в Интернете.

class BankAccount  attr_accessor :id, :amount  def initialize(id, amount)    @id = id    @amount = amount  endend
acct1 = BankAccount.new(213, 300)acct2 = BankAccount.new(22, 100)acct3 = BankAccount.new(222, 500)
accts = [acct1, acct2, acct3]
total_sum = 0accts.each do |eachAcct|  total_sum = total_sum + eachAcct.amountend
puts total_sum # =&gt; 900

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

Ввиду этого переменная, созданная внутри блока, доступна только для блока.

Управление доступом

Разрабатывая класс, важно подумать о том, какую часть вы откроете миру. Это известно как инкапсуляция, и обычно означает сокрытие внутреннего представления объекта.

У Ruby существует три уровня контроля доступа:

  • Общественный — контроль доступа не производится. Кто угодно может назвать эти методы.
  • Защищенный могут быть вызваны объектами определяющих классов или их подклассов.
  • Частный — не может быть вызван, кроме как посредством явного получателя.

Давайте посмотрим пример инкапсуляции в действии:

class Car  def initialize(speed, fuel_eco)    @rating = speed * comfort  end
  def rating    @rating  endend
puts Car.new(100, 5).rating # =&gt; 500

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

Если говорить о способах определения контроля доступа, то их два:

  1. Если указать общедоступный, защищенный или приватный, и все, пока следующее ключевое слово управления доступом будет иметь этот уровень контроля доступа.
  2. Регулярно определяйте метод, затем указывайте общедоступный, частный и защищенный уровни доступа и перечисляйте методы, разделенные запятыми (,), под этими уровнями с помощью символов методов.

Пример первого способа:

class MyClass  private    def func1      "private"    end  protected    def func2      "protected"    end  public    def func3      "Public"    endend

Пример второго способа:

class MyClass  def func1    "private"  end  def func2    "protected"  end  def func3    "Public"  end  private :func1  protected :func2  public :func3end

Примечание: часто используются публичные и частные средства управления доступом.

Вывод

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

Не забудьте аплодировать и следовать, если вам понравилось! Не отставай от меня здесь.

Добавить комментарий

Ваш адрес email не будет опубликован.