Просмотров-410
0

Объектно — ориентированное программирование на языке Crystal

Объектно ориентированное программирование

Принципы объектно-ориентированного программирования

Объектно-ориентированное программирование ( ООП ) — это парадигма программирования, основанная на концепции « объектов», которые могут содержать данные и код: данные в форме полей, часто называемые  атрибутами  или  свойствами,  и код в форме процедур, как правило, называемые методами. Любой современный объектно-ориентированный язык программирования позволяет создавать высокопроизводительное программное обеспечение.

Объектно-ориентированный язык программирования базируется на понятии «класс», который представляет собой пользовательский тип данных или шаблон для создания объектов – экземпляров класса. Тогда программа представляет собой совокупность взаимодействующих объектов.

Язык программирования называется объектно-ориентированным, если в нем реализованы следующие принципы:

  • инкапсуляции;
  • наследования;
  • полиморфизма.

Напомним эти определения.

Инкапсуляция – это  концепция объектно-ориентированного программирования, которая связывает воедино данные и функции(методы), которые манипулируют данными, и защищает их как от внешнего вмешательства, так и от неправильного использования(сокрытие данных и методов).

Наследование- это  возможность создания новых классов (подклассов, производных классов) из существующих базовых классов, с последующим формированием их в иерархию классов.

Производный класс наследует все переменные экземпляра и все методы экземпляра и класса(суперкласса), включая его конструкторы (new и initialize). Применение иерархии классов делает управляемыми большие потоки информации.

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

Примечание. Объекты, созданные из классов, занимают память в «общей куче» и сборщику мусора приходится освобождать эту область памяти. Как вы уже видели ранее на примере кода цикла в разделе «Структурирование класса», создание множества объектов может быстро истощить ресурсы ЭВМ.

Crystal  — это высокоуровневый объектно-ориентированный язык программирования, в котором реализованы все принципы ООП. Далее рассмотрим их реализацию подробнее. Основы синтаксиса будут сопровождаться примерами фрагментов программ, созданными в среде программирования Crystal.

Использование инкапсуляции в программах

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

Для реализации инкапсуляции в программах объектно-ориентированный язык программирования использует ограничение видимости (так называемая инкапсуляция кода). Управление доступом к переменным и методам класса осуществляется с помощью специальных ключевых слов public, protected или private, записываемых перед определением метода и означающих общедоступный, защищенный и закрытый, соответственно.

По умолчанию методы являются общедоступными, если нет  ключевого слова public.

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

Например, объявим класс, имеющий два атрибута и два метода.

  1. class Sensor                            #  имя класса
  2.   @izmPar: Float32                #  имя  переменной класса вещественного типа
  3.   def initialize(izmPar : Float32)   #  имя  метода класса(инициализация объекта)
  4.     @izmPar = izmPar                    # инициализация через параметр
  5.     @speed = 0                                    инициализация присваиванием
  6.   End
  7. def izmPar
  8.     @izmPar
  9.   end
  10.   def speed
  11.     @speed
  12.   end
  13. end

Если в этом классе вторую строчку записать так private  @izmPar: Float32, то получим ошибку:

Error: can’t apply visibility modifier

Ошибка: не удается применить модификатор видимости

Потому что модификатор видимости(доступа) применяется только к методам.

Если будет объявлен закрытый(частный) метод, например

private def izmPar

    @izmPar

  End

То использовать его в программе нельзя. Private метод может быть вызван только в том классе, где он объявлен.  Если так,

 sensor = Sensor.new(50,100)

sensor.izmPar,

то  применение sensor.izmPar в программе приведет к ошибке: Error: private method ‘izmPar’ called for Sensor — Ошибка: для Sensor вызван частный метод «» izmPar

Аналогично и для защищенного(protected) метода.

Кроме того, объявление метода с явным указанием модификатора видимости приводит к ошибке.

public def izmPar

    @izmPar

  end

Error: can’t declare def dynamically.

Ошибка: не удается динамически объявить def.

Как же быть? Ответ прост – выполнять закрытый или защищенный методы можно внутри другого открытого метода класса.

Дополняем класс методом

def izmMer

   puts sensor.izmPar

  end

Теперь

sensor = Sensor.new(50,100)

sensor.izmMer,

метод sensor.izmPar выполнится без ошибки.

Инкапсуляция в объектно-ориентированном языке программирования

Грамотное применение уровней доступа к элементам класса хорошо обеспечивает безопасность кода программы.

Перегрузка методов

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

Перегрузка методов осуществляется по нескольким критериям:

Количество аргументов

Ограничения типа, применяемые к аргументам

Принимает ли метод блок или нет

Например, ниже определяется четыре разных метода с одним именем:

  1. class Proba
  2.   @x: Int32
  3.   def initialize(x : Int32)
  4.     @x=x
  5.     puts «Начальное значение», «#{@x}»
  6.   end
  7.   # Увеличение значения на единицу
  8.   def increm
  9.     @x += 1
  10.   end
  11. # Увеличение значения на y
  12.   def increm(y : Int32)
  13.     @x += y
  14.   end
  15. # Увеличение значения начисло, заданное строкой str
  16.   def increm(str : String)
  17.     @x += str.to_i
  18.   end
  19. #Вырабатывает текущее значение и увеличивает его
  20. # на значение, возвращаемое блоком
  21.  def increm
  22.     @x += yield @x
  23.   end
  24. end
  25. Создаем объект класса 
  26. probn = Proba.new(3)
  27. Выполнякм методы с одним именем и различными параметрами.
  28. #probn.increm
  29. puts «Увеличенное значение на 1», probn.increm   #=> 4
  30. #probn.increm(6)
  31. puts «Увеличенное значение на 6», probn.increm(6)      #=> 10
  32. #probn.increm(«25»)
  33. puts «Увеличенное значение на 25», probn.increm(«25»)     #=> 36
  34. probn.increm  do |current_x|
  35.   current_x < 30 ? 15 : 40
  36. end
  37. puts «Увеличенное значение на число из блока», probn.increm    #=> 76
Объектно-ориентированный язык программирования - перегрузка методов

Использование наследования  в программах

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

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

Каждый класс, кроме Object - корня иерархии, наследуется от другого класса (его суперкласса). 

 Синтаксис объявления производного класса Temp от базового Sensor  имеет вид.

class Temp < Sensor               #объявлен пустой класс

end

Далее в программе запишем

sensor = Sensor.new(50,100)

temp=Temp.new(30,69)         #создание объекта произвольного класса

sensor.izmPar  #так нельзя:

Error: protected method ‘izmPar’ called for Sensor

Ошибка: для Sensor вызван защищенный метод izmPar

temp.izmPar    #так можно, класс Temp наследует метод izmPar класса Sensor.

Класс Temp  наследует все переменные и все методы суперкласса Sensor, включая его конструкторы ( new и initialize).

Методы в производном классе можно дополнять и переопределять. Но вызывать не переопределенные методы суперкласса нельзя. Например.

class Temp < Sensor

  self.izmPar

end

Возникает ошибка на этапе компиляции.

Error: undefined method ‘izmPar’ for Temp.class

Ошибка: неопределенный метод  “izmPar” для Temp.class

Объектно-ориентированный язык программирования -наследование

Можно также переопределить любой унаследованный метод в подклассе. Если подкласс определяет собственные методы initialize для инициализации, то они не наследуются. Если вы хотите использовать функциональность суперкласса после его переопределения, можно вызвать любой метод суперкласса с помощью «super»

Использование полиморфизма  в программах

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

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

  1. Class sumInt
  2. n=10
  3. def summa(self,n)
  4.   self.summa= self.n + n
  5. end
  6. end
  7. Class sumString
  8. n=10
  9. def summa(self,s)
  10.   self.summa= len(snr(s)
  11. end
  12. end
  13. si =  sumInt()
  14. ss =  sumString()
  15. si.summa(45)     
  16. нss.summa(45)
  17. print(si.summa)      # результат 55
  18. print(ss.summa)      # результат 2

В данном примере метод с одним и тем же именем summa() используется как для суммирования целых чисел, так и для определения количества цифр в числе(длины строки).

Пример использования ООП для решения задачи

Для примера использования ООП в языке программировании Crystal рассмотрим задачу измерения температуры и давления воздуха. Для получения измерений  применяется два датчика – один в качестве датчика температуры, другой  — датчика давления.

В программе предусматривается базовый класс Sensor, отражающий общие свойства любого датчика, и два производных от него класса SensorTemp  и  SensorDavl, соответственно, представляющие объекты — датчик температуры и давления. Измерения передаются в эти классы для хранения.

В качестве измеренного значения формируется среднее арифметическое всех измерений — сумма всех измерений, деленная на их количество. Для этого создается отдельный класс Izmer, в котором в методе srZnach осуществляется суммирование элементов массива измерений и вычисление среднего значения.

Код программы.

  1. class Sensor                #измеритель — базовый класс
  2.    @n=5
  3.    @k=15
  4.   @sum=0
  5.              @izmPar =[] of Float64    #создаем пустой массив Array(Float64)
  6.   def initialize(@n : Int32, @k : Int32, izmPar=[] of Float64)
  7.             z = gen(n,k,izmPar)  # генерируем массив izmPar(Float64) из n элементов
  8. #          puts izmPar # оператор для отладки программы
  9.   end
  10.    def gen(n,k,mas=[] of Float64)
  11.              i=0
  12.                         while i<n
  13.              mas<<k+0.01*k*rand
  14.                            i+=1
  15.                          end
  16. #    puts mas # оператор для отладки программы
  17.    end
  18. end
  1. class SensorTemp  < Sensor  #измеритель температуры — производный класс
  2.             def srTemp                 # метод вычисления среднего значения температуры
  3.             end
  4. end

  1. class SensorDavl  < Sensor  #измеритель давления — производный класс
  2.  def srDavl                 # метод вычисления среднего значения давления
  3.             end
  4. end
  1. class Izmer  # вычислитель самостоятельный класс
  2.   def initialize()
  3.   end
  4.    def srZnach(n,mas=[] of Float64)
  5.              i=0
  6.     sum=0
  7.                         while i<n
  8.              sum += mas[i]
  9.                            i+=1
  10.                          end
  11.     srZnach=sum/n
  12. #    puts «Среднее в классе», srZnach # оператор для отладки программы
  13.     return srZnach
  14.    end
  15. end

# Программа вычисления температуры и давления воздуха.

  1. puts «Имитация измерителя температуры и давления»
  2. n=5
  3. srGenT=25
  4. srGenD=760
  5. izmPar =[] of Float64    #создаем пустой массив Array(Float64)
  6. sensor = Sensor.new(n,5,izmPar)
  7.  izmer=Izmer.new()
  8. izmTemp =[] of Float64
  9. sensTemp = SensorTemp.new(n,srGenT,izmTemp)
  10. printf «Массив температур  —  «
  11. #puts «\n», izmTemp # оператор для отладки программы
  12. izmTemp.each_with_index{ |n, idx| print «%#{3.2}f » % n; print «\n» if idx % 10 == 5 }
  13. srTemp=izmer.srZnach(n,izmTemp)
  14. puts «\n», «Средняя температура», «%3.2f» %srTemp
  15. izmDavl =[] of Float64
  16. sensDavl = SensorDavl.new(n,srGenD,izmDavl)
  17. printf «Массив давлений  —  «
  18. izmDavl.each_with_index{ |n, idx| print «%#{3.2}f » % n; print «\n» if idx % 10 == 5 }
  19. srDavl=izmer.srZnach(n,izmDavl)
  20. puts «\n», «Среднее давление», «%3.2f» %srDavl

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

Объектно-ориентированный язык программирования - пример программы

Анализ представленных результатов свидетельствует о работоспособности программы на языке Crystal.

Заключение

Crystal  — это высокоуровневый объектно-ориентированный язык программирования.

Инкапсуляция используется в программах для сокрытия значений или состояния объекта структурированных данных внутри класса.

 В языке Crystal предусмотрено одиночное наследование классов.

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

Статьи по теме

Простые типы данных
языка программирования Crystal
Язык программирования CrystalИзучение управляющих
конструкций языка
программирования Crystal
Изучение языка программирования Crysal Управляющие конструкции
Процедурное
программирование
на языке Crystal
Процедурное программирование на языке CrystalСтруктурированные
типы данных языка
программирования Crystal
Структурированные типы данных
  1. Что такое программирование?
  2. Как выбирать язык программирования высокого уровня для изучения
  3. Что выбирать язык или платформу программирования?
  4. Онлайн школы и курсы программирования
  5. Как изучать алгоритмы решения задач?
  6. Как изучать простые типы данных языка программирования?
  7. Как стать специалистом по большим данным?
Кто хочет своевременно узнавать о выходе новой статьи на сайте должен подписаться.

ПОДПИСКА НА РАССЫЛКУ

Статьи об онлайн курсах обучения

Дистанционное обучение
Обучение программированию
Проектирование информационных систем
 

brasm

Пенсионер с 33 - летним педагогическим стажем

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *