Ruby orienté objet

Ruby est un langage purement orienté objet, et tout dans Ruby prend la forme d'objets. Chaque valeur en Ruby est un objet, même les choses les plus primitives : les chaînes de caractères, les nombres, et même true et false sont des objets. La classe elle-même est aussi unobjet, qui estClassune instance de la classe Class. Ce chapitre expliquera toutes les principales fonctionnalités liées à la programmation orientée objet en Ruby.

Les classes sont utilisées pour spécifier la forme des objets. Elles combinent la représentation des données et les méthodes, en organisant les données dans un ensemble bien organisé. Les données et les méthodes d'une classe sont appelées membres de la classe.

Définition de classe Ruby

Lorsque vous définissez une classe, vous définissez en réalité un plan pour un type de données. Cela ne définit pas réellement de données, mais définit plutôt ce que signifie le nom de la classe, c'est-à-dire de quoi seront constitués les objets de la classe et quelles opérations pourront être effectuées sur l'objet.

Une définition de classe commence par le mot-cléclasset est suivie parle nom de la classe, et se termine enfin parendun séparateur pour marquer la fin de la définition de la classe. Par exemple, nous utilisons le mot-clé class pour définir la classe Box, comme montré ci-dessous :

class Box code end

Par convention, le nom doit commencer par une lettre majuscule. S'il contient plusieurs mots, mettez en majuscule la première lettre de chaque mot, mais sans séparateur entre eux (par exemple, CamelCase).

Définition d'objets Ruby

Les classes fournissent le plan pour les objets, donc en gros, les objets sont créés à partir de la classe. Nous utilisons lenewmot-clé pour déclarer des objets de la classe. L'instruction suivante déclare deux objets de la classe Box :

box1 = Box.new box2 = Box.nouveau

La méthode initialize

initializeLa méthode est une méthode de classe Ruby standard, servant de constructeur de classe, et est similaire auconstructeurprincipe de fonctionnement dans d'autres langages de programmation orientés objet. Lorsque vous voulez initialiser certaines variables de classe lors de la création d'un objet, la méthode initialize est utile. Cette méthode prend une série de paramètres ; comme les autres méthodes Ruby, lorsque vous l'utilisez, vous devez placer ledefmot-clé avant celui-ci, comme montré ci-dessous :

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

Variables d'instance

Les variables d'instancesont des attributs de classe. Lorsque des objets sont créés à l'aide de la classe, elles deviennent les attributs des objets. Les attributs de chaque objet sont assignés séparément et ne partagent pas leurs valeurs avec d'autres objets. À l'intérieur de la classe, ces attributs sont accessibles à l'aide de l'opérateur @ ; à l'extérieur de la classe, ils sont accessibles à l'aide de méthodes appeléesméthodes d'accès, qui sontdesméthodes publiques. Ci-dessous, nous prenons la classe définie ci-dessusBoxcomme exemple, et utilisons @width et @height comme variables d'instance de la classe Box.

class Box def initialize(w,h) #Affectation de valeurs aux variables d'instance @width, @height = w, h end end

Méthodes d'accès (getter) et de modification (setter)

Pour lire des variables définies dans une classe depuis l'extérieur de la classe, nous pouvons définir des méthodes d'accès (getter) pour y accéder. L'exemple suivant illustre l'utilisation des méthodes d'accès :

Exemple

#!/usr/bin/ruby -w #Définir la classe class Box #Constructeur def initialize(w,h) @width, @height = w, h end #Méthodes d'accès def printWidth @width end def printHeight @height end end #Créez un objet et initialisez la hauteur et la largeur de la boîte box = Box.new(10, 20) #Utiliser des méthodes d'accès x = box.printWidth() y = box.printHeight() puts "Box width : #{x}" puts "Box height : #{y}"

Essayez-le »

Lorsque le code ci-dessus est exécuté, il produit le résultat suivant :

盒子宽度 : 10
盒子高度 : 20

Comme les méthodes d'accès utilisées pour accéder aux valeurs des variables, Ruby permet de transmettre des paramètres aux variables définies dans une classe depuis l'extérieur de la classe, ce que l'on appelle lesméthodes d'assignation, définies comme suit :

Exemple

#!/usr/bin/ruby -w #Définir la classe class Box #Méthode constructeur def initialize(w,h) @width, @height = w, h end #Méthodes d'accès def getWidth @width end def getHeight @height end #Méthodes d'assignation def setWidth=(value) @width = value end def setHeight=(value) @height = value end end #Créer des objets box = Box.new(10, 20) #Utiliser les méthodes setter box.setWidth = 30 box.setHeight = 50 #Utiliser les méthodes d'accès x = box.getWidth() y = box.getHeight() puts "Largeur de la boîte : #{x}" puts "Box height : #{y}"

Essayez-le »

Lorsque le code ci-dessus est exécuté, il produit le résultat suivant :

盒子宽度 : 30
盒子高度 : 50

Comme ces deux méthodes sont très couramment utilisées, Ruby définitattr_accessor :variable_name、attr_reader :variable_name、attr_writer :variable_nametrois méthodes de déclaration d'attributs. Parmi elles :accesseur=lecteur+écrivain。

Remarque : le nom de la variable doit être précédé de:, et entre les noms de variables, utilisez,pour les séparer.

Méthodes d'instance

Les méthodes d'instancesont définies de la même manière que les autres méthodes, en utilisant le mot-clédef, mais elles ne peuvent être utilisées que via des instances de classe, comme le montre l'exemple ci-dessous. Leurs fonctions ne se limitent pas à accéder aux variables d'instance ; elles peuvent également effectuer de nombreuses autres tâches selon les besoins.

Exemple

#!/usr/bin/ruby -w #Définir la classe class Box #Méthode constructeur def initialize(w,h) @width, @height = w, h end #Méthode d'instance def getArea @width * @height end end #Créer des objets box = Box.new(10, 20) #Appeler la méthode d'instance a = box.getArea() puts "L'aire de la boîte est : #{a}"

Essayez-le »

Lorsque le code ci-dessus est exécuté, il produit le résultat suivant :

Area of the box is : 200

Méthodes de classe et variables de classe

Variables de classesont des variables partagées par toutes les instances d'une classe. En d'autres termes, les variables de classe sont accessibles par toutes les instances d'objet. Les variables de classe sont préfixées par deux caractères @ (@@). Les variables de classe doivent être initialisées dans la définition de la classe, comme montré dans l'exemple ci-dessous.

Méthodes de classesont définies à l'aide dudef self.methodname()mot-clé, et les méthodes de classe se terminent par le délimiteur end. Les méthodes de classe peuvent être appelées en utilisant laclassname.methodnameforme avec le nom de la classe, comme montré dans l'exemple ci-dessous :

Exemple

#!/usr/bin/ruby -w class Box #Initialiser les variables de classe @@count = 0 def initialize(w,h) #Affecter des valeurs aux variables d'instance @width, @height = w, h @@count += 1 end def self.printCount() puts "Le nombre de Box est : #@@count" end end #Créer deux objets box1 = Box.new(10, 20) box2 = Box.new(30, 100) #Appeler la méthode de classe pour afficher le nombre de boîtes Box.printCount()

Essayez-le »

Lorsque le code ci-dessus est exécuté, il produit le résultat suivant :

Box count is : 2

La méthode to_s

Toute classe que vous définissez possède une méthode d'instanceto_spour renvoyer la représentation sous forme de chaîne de l'objet. Voici un exemple simple représentant des objets Box en fonction de la largeur et de la hauteur :

Exemple

#!/usr/bin/ruby -w class Box #Méthode constructeur def initialize(w,h) @width, @height = w, h end #Définir la méthode to_s def to_s "(w:#@width,h:#@height)" #Le format de chaîne de l'objet end end #Créer des objets box = Box.new(10, 20) #La méthode to_s est appelée automatiquement puts "La représentation sous forme de chaîne de box est : #{box}"

Essayez-le »

Lorsque le code ci-dessus est exécuté, il produit le résultat suivant :

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

Contrôle d'accès

Ruby vous offre trois niveaux de protection des méthodes d'instance, à savoirpublic, private ou protected. Ruby n'applique aucun contrôle d'accès aux variables d'instance et de classe.

  • Méthodes publiques :Les méthodes publiques peuvent être appelées par n'importe quel objet. Par défaut, les méthodes sont publiques, sauf la méthode initialize, qui est toujours privée.
  • Méthodes privées :Les méthodes privées ne peuvent pas être accessibles ni consultées depuis l'extérieur de la classe. Seules les méthodes de classe peuvent accéder aux membres privés.
  • Méthodes protégées :Les méthodes protégées ne peuvent être appelées que par des objets de la classe et de ses sous-classes. L’accès ne peut également se faire qu’à l’intérieur de la classe et de ses sous-classes.

Voici un exemple simple illustrant la syntaxe de ces trois modificateurs :

Exemple

#!/usr/bin/ruby -w #Définir la classe class Box #Méthode constructeur def initialize(w,h) @width, @height = w, h end #Les méthodes d’instance sont publiques par défaut def getArea getWidth() * getHeight end #Définir des méthodes d’accesseur privées def getWidth @width end def getHeight @height end # les rendre privées private :getWidth, :getHeight #Une méthode d’instance pour afficher l’aire def printArea @area = getWidth() * getHeight puts "L’aire de la grande boîte est : #@area" end #Rendre la méthode d’instance protégée protected :printArea end #Créer des objets box = Box.new(10, 20) #Appeler des méthodes d’instance a = box.getArea() puts "L'aire de la boîte est : #{a}" #Essayer d’appeler la méthode d’instance protégée box.printArea()

Essayez-le »

Lorsque le code ci-dessus est exécuté, il produit le résultat suivant. Ici, le premier appel de méthode réussit, mais le second appel de méthode pose un problème.

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

Héritage de classe

L'héritage est l'un des concepts les plus importants de la programmation orientée objet. L'héritage nous permet de définir une classe à partir d'une autre classe, ce qui facilite la création et la maintenance des applications.

L'héritage facilite la réutilisation du code et une exécution rapide. Malheureusement, Ruby ne prend pas en charge l'héritage multiple, mais Ruby prend en chargemixinsmixins. Les mixins sont comme une implémentation spécifique de l'héritage multiple, où seule la partie interface est héritable.

Lors de la création d'une classe, le programmeur peut spécifier directement que la nouvelle classe hérite des membres d'une classe existante, évitant ainsi d'écrire de nouveaux membres de données et fonctions membres à partir de zéro. Cette classe existante est appeléeclasse de base ou classe parente, et la nouvelle classe est appeléeclasse dérivée ou sous-classe。

Ruby fournit également le concept de sous-classement, qui est l'héritage. L'exemple suivant explique ce concept. La syntaxe pour étendre une classe est très simple. Ajoutez simplement un caractère < et le nom de la classe parente à l'instruction class. Par exemple, ce qui suit définit la classeBigBoxest uneBoxsous-classe :

Exemple

#!/usr/bin/ruby -w #Définir la classe class Box #Méthode constructeur def initialize(w,h) @width, @height = w, h end #Méthode d'instance def getArea @width * @height end end #Définir la sous-classe class BigBox < Box #Ajouter une nouvelle méthode d'instance def printArea @area = @width * @height puts "La surface de la grande boîte est : #@area" end end #Créer un objet box = BigBox.new(10, 20) #Afficher l'aire box.printArea()

Essayez-le »

Lorsque le code ci-dessus est exécuté, il produit le résultat suivant :

Big box area is : 200

Surcharge de méthode

Bien que vous puissiez ajouter de nouvelles fonctionnalités dans une classe dérivée, vous pouvez parfois vouloir modifier le comportement d'une méthode déjà définie dans la classe parente. Dans ce cas, vous pouvez conserver le nom de la méthode inchangé et redéfinir la fonctionnalité de la méthode, comme illustré dans l'exemple suivant :

Exemple

#!/usr/bin/ruby -w #Définir la classe class Box #Méthode constructeur def initialize(w,h) @width, @height = w, h end #Méthode d'instance def getArea @width * @height end end #Définir la sous-classe class BigBox < Box #Modifier la méthode getArea existante def getArea @area = @width * @height puts "La surface de la grande boîte est : #@area" end end #Créer un objet box = BigBox.new(10, 20) #Utiliser la méthode redéfinie pour afficher l'aire box.getArea()

Essayez-le »

La sortie de l'exemple ci-dessus est :

Big box area is : 200

Surcharge des opérateurs

Nous voulons utiliser l'opérateur + pour effectuer l'addition vectorielle de deux objets Box, utiliser l'opérateur * pour multiplier la largeur et la hauteur de Box, et utiliser l'opérateur unaire - pour inverser le signe de la largeur et de la hauteur de Box. Voici une version de la classe Box avec des définitions d'opérateurs mathématiques :

class Box def initialize(w,h) #Initialiser la largeur et la hauteur @width,@height = w, h end def +(other) #Définir + pour effectuer une addition vectorielle Box.new(@width + other.width, @height + other.height) end def -@ #Définir l'opérateur unaire - pour inverser le signe de la largeur et de la hauteur Box.new(-@width, -@height) end def *(scalar) #Effectuer une multiplication scalaire Box.new(@width*scalar, @height*scalar) end end

Gel des objets

Parfois, nous voulons empêcher les objets d'être modifiés. Dans Object, la méthode freeze peut y parvenir, transformant effectivement un objet en constante. Tout objet peut être gelé en appelantObject.freezefreeze. Un objet gelé ne peut pas être modifié, c'est-à-dire que vous ne pouvez pas modifier ses variables d'instance.

Vous pouvez utiliser la méthodeObject.frozen?pour vérifier si un objet donné a été gelé. Si l'objet est gelé, cette méthode renvoie true ; sinon, elle renvoie une valeur false. L'exemple suivant explique ce concept :

Exemple

#!/usr/bin/ruby -w #Définir la classe class Box #Méthode constructeur def initialize(w,h) @width, @height = w, h end #Méthode d'accès def getWidth @width end def getHeight @height end #Méthode d'assignation def setWidth=(value) @width = value end def setHeight=(value) @height = value end end #Créer un objet box = Box.new(10, 20) #Gelons l'objet box.freeze if( box.frozen? ) puts "L'objet Box est un objet gelé" else puts "L'objet Box est un objet normal" end #Essayez maintenant d'utiliser la méthode setter box.setWidth = 30 box.setHeight = 50 #Utilisez la méthode accesseur x = box.getWidth() y = box.getHeight() puts "La largeur de la boîte est : #{x}" puts "La hauteur de la boîte est : #{y}"

Essayez-le »

Lorsque le code ci-dessus est exécuté, il produit le résultat suivant :

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

Constantes de classe

Vous pouvez définir une constante à l'intérieur d'une classe en affectant directement une valeur numérique ou une chaîne à une variable. Les constantes n'ont pas besoin d'utiliser @ ou @@. Par convention, les noms des constantes sont en majuscules.

Une fois qu'une constante est définie, vous ne pouvez pas modifier sa valeur. Vous pouvez accéder à la constante directement à l'intérieur de la classe, comme pour accéder à une variable, mais si vous souhaitez accéder à la constante en dehors de la classe, vous devez utiliserclassname::constant::, comme indiqué dans l'exemple suivant.

Exemple

#!/usr/bin/ruby -w #Définir la classe class Box BOX_COMPANY = "TATA Inc" BOXWEIGHT = 10 #Méthode constructeur def initialize(w,h) @width, @height = w, h end #Méthode d'instance def getArea @width * @height end end #Créer un objet box = Box.new(10, 20) #Appeler une méthode d'instance a = box.getArea() puts "L'aire de la boîte est : #{a}" puts Box::BOX_COMPANY puts "Le poids de Box est : #{Box::BOXWEIGHT}"

Essayez-le »

Lorsque le code ci-dessus est exécuté, il produit le résultat suivant :

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

Les constantes de classe peuvent être héritées et peuvent aussi être redéfinies comme les méthodes d'instance.

Création d'objets en utilisant allocate

Il peut arriver que vous souhaitiez créer un objet sans appeler le constructeur d'objetinitialize, c'est-à-dire sans utiliser la méthode new pour créer un objet. Dans ce cas, vous pouvez appeler allocate pour créer un objet non initialisé, comme le montre l'exemple suivant :

Exemple

#!/usr/bin/ruby -w #Définir la classe class Box attr_accessor :width, :height #Méthode constructeur def initialize(w,h) @width, @height = w, h end #Méthode d'instance def getArea @width * @height end end #Créer un objet en utilisant new box1 = Box.new(10, 20) #Créer un autre objet en utilisant allocate box2 = Box.allocate #Appeler une méthode d'instance en utilisant box1 a = box1.getArea() puts "L'aire de la boîte est : #{a}" #Appeler une méthode d'instance en utilisant box2 a = box2.getArea() puts "L'aire de la boîte est : #{a}"

Essayez-le »

Lorsque le code ci-dessus est exécuté, il produit le résultat suivant :

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

Informations sur la classe

Le self de Ruby et le this de Java présentent des similitudes, mais sont aussi assez différents. En Java, les méthodes sont référencées dans les méthodes d'instance, donc this pointe généralement vers l'objet courant. Le code Ruby s'exécute ligne par ligne, donc self a des significations différentes selon le contexte. Regardons l'exemple suivant :

Exemple

#!/usr/bin/ruby -w class Box #Afficher les informations de la classe puts "Classe de self = #{self.class}" puts "Nom de self = #{self.name}" end

Essayez-le »

Lorsque le code ci-dessus est exécuté, il produit le résultat suivant :

Class of self = Class
Name of self = Box

Cela signifie que la définition de classe peut être exécutée en traitant la classe comme l'objet courant, et cela signifie aussi que les méthodes de la métaclasse et de la classe parente sont disponibles pendant l'exécution de la définition de méthode.

Autres extensions