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

Опубликовано: 31 Января, 2022

В программировании на R ООП предоставляет классы и объекты в качестве ключевых инструментов для уменьшения сложности программы и управления ею. R - это функциональный язык, использующий концепции ООП. Мы можем думать о классе как об эскизе автомобиля. Он содержит все подробности о model_name, model_no, двигателе и т. Д. На основе этих описаний мы выбираем автомобиль. Автомобиль - это объект. Каждый автомобильный объект имеет свои особенности и особенности. Объект также называется экземпляром класса, а процесс создания этого объекта называется созданием экземпляра. ООП имеет следующие особенности:

  • Класс
  • Объект
  • Абстракция
  • Инкапсуляция
  • Полиморфизм
  • Наследование

Класс и объект

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

    Пример: объект Кеша и Адам являются производными от одного и того же ученика класса, но имеют разные свойства, такие как имя и номер списка.

Для лучшего понимания давайте обсудим два наиболее важных класса в R:

  • S3 Class
    S3 class does not have a predefined definition and able to dispatch. In this class, the generic function makes a call to the method. Easy implementation of S3 is possible because it differs from the traditional programming language Java, C++, and C# which implements Object Oriented message passing.

    Creating S3 class:

    Syntax:

    variable_name <- list(attribute1, attribute2, attribute3....attributeN)

    Example:
    In the following code a Student class is defined. Appropriate class name is given having attributes student’s name and roll number. Then the object of student class is created and invoked.

    # List creation with its attributes name and roll no.
    a <- list(name = "Adam", Roll_No = 15 )  
      
    # Defining a class "Student"
    class(a) <- "Student"  
      
    # Creation of object
    a

    Output:

    $name
    [1] "Adam"
    
    $Roll_No
    [1] 15
    
    attr(, "class")
    [1] "Student"
  • S4 Class
    S4 class has a predefined definition. It contains functions for defining methods and generics. It makes multiple dispatches easy. This class contains auxiliary functions for defining methods and generics.

    Creating S4 class: setClass() command is used to create S4 class. Following is the syntax for setclass command which denotes myclass with slots containing name and rollno.

    Syntax:



     setClass("myclass", slots=list(name="character", Roll_No="numeric"))  

    Example:

    # Function setClass() command used 
    # to create S4 class containing list of slots.
    setClass("Student", slots=list(name="character"
                                   Roll_No="numeric"))
      
    # "new" keyword used to create object of class "Student"   
    a <- new("Student", name="Adam", Roll_No=20)  
      
    # Calling object
    a

    Output:

    Slot "name":
    [1] "Adam"
    
    Slot "Roll_No":
    [1] 20

The reasons for defining both S3 and S4 class are as follows:

  • S4 class alone will not be seen if the S3 generic function is called directly. This will be the case, for example, if some function calls unique() from a package that does not make that function an S4 generic.
  • However, primitive functions and operators are exceptions: The internal C code will look for S4 methods if and only if the object is an S4 object. S4 method dispatch would be used to dispatch any binary operator calls where either of the operands was an S4 object.
  • S3 class alone will not be called if there is any eligible non-default S4 method.

So if a package defined an S3 method for unique for an S4 class but another package defined an S4 method for a superclass of that class, the superclass method would be chosen, probably not what was intended.

Inheritance

Inheritance is an important concept in OOP(object-oriented programming) which allows one class to derive the features and functionalities of another class. This feature facilitates code-reusability.

Example:
In the following code, inheritance is done using S3 class, firstly the object is created of the class student.

# student function with argument name(n) and roll_no(r)
student <- function(n, r) {
     value <- list(name=n, Roll=r)
     attr(value, "class") <- "student"
     value
}

Then, method is defined to print the details of student.

# "print.student" method created
print.student <- function(obj) {
  
     # "cat" function is used to concatenate strings
     cat("Name:", obj$name, " ")
     cat("Roll", obj$roll, " ")}

Now, inheritance is done while creating another class by doing class(obj) <- c(child, parent).

s <- list(name="Kesha", Roll=21, country="India")
   
# child class "Student" inherits
# parent class "student" 
class(s) <- c("Student", "student")
s

Output:

Name: Kesha 
Roll: 21 

The following code overwrites the method for class student.

# "Student" class object is passed
# in the function of class "student"
print.student <- function(obj) {
    cat(obj$name, "is from", obj$country, " ")
}
s

Output:

Kesha is from India 

Polymorphism

R methods belong to functions, not classes and thus it is also known as parametric polymorphism. Parametric polymorphism defines a generic method or function for types of objects you haven’t yet defined and may never do. This means that one can use the same name for various functions with different sets of arguments and from different classes.

R must have a mechanism to know which names require simple function calls and which names require method calls. This mechanism is called generics. Generics allows you to register certain names to be treated as methods in R, and they act as dispatchers. When these registered generic functions are called, R looks into a chain of attributes in the object being passed in the call to look for functions that match the method call for that object’s type. If it finds a function, it will call that function.

Encapsulation

Encapsulation is about hiding an object’s properties from other objects. It hides information to prevent mistakes and compromise security. Though objects are allowed to communicate with each other using public methods and all the data is transferred between objects using these public methods. Hence this way data in objects remain private while also giving them the freedom to transfer and manipulate that data using methods. It adds an extra layer of security. And this process of separating interface from implementation is called Encapsulation.

Example:

s <- list(country = "India"
          state = "Delhi", street_no.= 110)
  
# Class name declared as "address"  
class(s) <- "address"
  
# Object creation of class "address".
s

Output:

$country
[1] "India"

$state
[1] "Delhi"

$street_no.
[1] 110

attr(, "class")
[1] "address"

Analogy such as this would help to understand better – When a user orders something from a website, he just wants to pay and receive his product. It won’t be a good thing to let the user know the internal working of the system that how his order is placed and where it goes.

Abstraction

Currently, this feature of OOPs in R is in the experimental stage, the behavior may change in the future.
Reference: Abstraction