【Ruby】オブジェクト指向が手に取るように理解できる入門5ステップ

Rubyプログラミング言語のロゴとオブジェクト指向のイメージ図Ruby
この記事は約14分で読めます。

 

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

基本的な知識があればカスタムコードを使って機能追加、目的を達成できるように作ってあります。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を凌駕する現役のプログラマチームによって監修されています。

サイト内のコードを共有する場合は、参照元として引用して下さいますと幸いです

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

あなたは、今手に持っているツールを最大限に活用できていますか?

これは、Rubyというプログラミング言語を学んでいるあなたに向けての問いかけです。

Rubyはその美しさと効率性から多くの開発者に支持されていますが、その真の力を引き出すためには、オブジェクト指向という考え方を理解することが必要不可欠です。

この記事を読むことで、Rubyのオブジェクト指向の基本から応用までを5つのステップで理解し、それを活用することができるようになります。

それぞれのステップで詳細なサンプルコードを表し、どのように動作するのか、何を意味しているのかを丁寧に解説します。

それでは、一緒にRubyのオブジェクト指向を学びましょう!

●Rubyとオブジェクト指向とは

オブジェクト指向プログラミング(OOP)は、それぞれが独立した「オブジェクト」としてデータと処理を一体化させる手法です。

RubyはそのようなOOPの原則を取り入れたプログラミング言語であり、そのメリットをフルに活用することで、効率よくメンテナンス可能なコードを書くことができます。

OOPでは、保守がしやすく、拡張性が高く、またコードの再利用が可能な設計が推奨されます。

Rubyはこれを「美しいコード」として具体化し、開発者が効果的にシステム設計を行えるよう支援します。

まずは、Rubyにおけるオブジェクト指向の基本的な構造とその概念について深く掘り下げてみましょう。

○Rubyの基本的な特徴

Rubyは、1995年に松本行弘さんによって作られたプログラミング言語です。

Rubyは人間中心設計をモットーに開発され、シンプルで読みやすい構文が特徴です。

また、Rubyは純粋なオブジェクト指向言語であり、全てがオブジェクトとして扱われます。

これにより、プログラミングがより直感的で理解しやすいものになります。

○オブジェクト指向の基本的な概念

オブジェクト指向は、プログラムを一連の「オブジェクト」の集まりとして考える方法論です。

「オブジェクト」とは、データとそのデータを操作するための「メソッド(関数)」が一つにまとまったものを指します。

オブジェクト指向は、プログラムをより現実世界に近い形で表現でき、複雑なシステムでも管理しやすくするという利点があります。

●Rubyにおけるオブジェクト指向の基本

オブジェクト指向の基本を習得することは何よりも重要です。

Rubyでオブジェクト指向設計を行う上で理解すべき基本概念には、クラス、インスタンス、メソッド、属性などが含まれます。

これらはRubyプログラムの構造と動作の土台となり、柔軟で再利用可能なコードを書くための出発点です。

まずは、これらの基本的な要素がどのように協力し合い、複雑な問題の解決に寄与するのかを見ていく必要があります。

クラスを定義しインスタンスを生成するプロセスから始め、メソッドと属性の関連を探り、Rubyでの実装方法を学んでいきましょう。

○クラスとインスタンス

Rubyにおけるオブジェクト指向の基本概念は、「クラス」と「インスタンス」です。

クラスはオブジェクトの設計図のようなもので、どのようなデータとメソッドを持つかを定義します。

一方、インスタンスはその設計図(クラス)に基づいて

作られた具体的なオブジェクトのことを指します。

○メソッドと属性

メソッドはクラスが持つ動作(関数)のことで、クラスが持つデータ(属性)を操作します。

Rubyでは、メソッドを呼び出すために「オブジェクト.メソッド名」の形式を使います。

○サンプルコード1:Rubyでのクラスとインスタンスの作成

このコードでは、クラスとインスタンスを使って簡単なプログラムを作成する方法を紹介しています。

この例では、Animalという名前のクラスを定義し、そのクラスを元にcatというインスタンスを作成しています。

class Animal
  def initialize(name)
    @name = name
  end

  def say_hello
    puts "こんにちは、#{@name}です"
  end
end

cat = Animal.new('たま')
cat.say_hello

ここではまずAnimalというクラスを定義しています。

このクラスはinitializesay_helloという2つのメソッドを持っています。

initializeはRubyにおける特別なメソッドで、インスタンスが生成されるときに自動的に呼び出されます。

このinitializeメソッドでは、インスタンスの属性(ここでは@name)を初期化しています。

次にcat = Animal.new('たま')というコードで、Animalクラスのインスタンスを生成し、そのインスタンスをcatという変数に代入しています。

newはRubyにおける特別なメソッドで、クラスのインスタンスを生成します。

ここでは'たま'という文字列をAnimal.newの引数として渡していますが、これがinitializeメソッドの引数nameとして受け取られ、@name属性の初期値として設定されます。

最後にcat.say_helloというコードで、say_helloメソッドを呼び出しています。

このメソッドは"こんにちは、#{@name}です"というメッセージを出力します。

ここでは@nameには先程Animal.newの引数として渡した'たま'が設定されているため、"こんにちは、たまです"というメッセージが出力されます。

このコードを実行すると、次のような結果が得られます。

こんにちは、たまです

このように、クラスとインスタンスを使うことで、一連のデータと操作(メソッド)を一つのまとまり(オブジェクト)として扱うことができます。

○サンプルコード2:Rubyでのメソッドと属性の使い方

次のコードでは、メソッドと属性を使ってオブジェクトの内部状態を変更し、その結果を出力する例を示しています。

この例では、Animalクラスのインスタンスに年齢を設定し、その年齢に応じたメッセージを出力しています。

class Animal
  def initialize(name)
    @name = name
    @age = 0
  end

  def set_age(age)
    @age = age
  end

  def say_age
    if @age <= 1
      puts "#{@name}はまだ子供です"
    elsif @age <= 3
      puts "#{@name}は若者です"
    else
      puts "#{@name}は大人です"
    end
  end
end

cat = Animal.new('たま')
cat.set_age(2)
cat.say_age

このコードでは、Animalクラスにset_agesay_ageという2つの新しいメソッドを追加しています。

set_ageメソッドは引数として受け取った年齢を@age属性に設定します。

say_ageメソッドは@age属性の値に応じたメッセージを出力します。

そして、cat = Animal.new('たま')でインスタンスを作成した後、cat.set_age(2)でそのインスタンスの年齢を設定し、cat.say_ageでその年齢に応じたメッセージを出力しています。

このコードを実行すると、次のような結果が得られます。

たまは若者です

このように、メソッドと属性を使うことで、オブジェクトの内部状態を操作し、その状態に応じた動作をさせることができます。

●オブジェクト指向の応用

オブジェクト指向の応用は、基本的な概念を超えた高度な設計パターンやコーディング手法を理解することを含みます。

継承は、コードの再利用を促す一方で、ポリモーフィズムによって異なるオブジェクトが一貫したインターフェイスを持つことができます。

これにより、プログラムはよりモジュラーで、柔軟性があり、拡張が容易になります。

サンプルコードでの継承の実例を通じて、それぞれの特徴をいかにして利用し、異なる振る舞いを持たせることができるのかを具体的に見ていきましょう。

○継承とポリモーフィズム

オブジェクト指向の応用として、継承とポリモーフィズムがあります。

継承は一つのクラスの特性(メソッドや属性)を別のクラスが引き継ぐことを指し、コードの再利用を容易にします。

ポリモーフィズムは、同一のインターフェースで異なる動作をすることを可能にし、コードの柔軟性を高めます。

○サンプルコード3:Rubyでの継承とポリモーフィズムの利用

次のコードでは、継承とポリモーフィズムを使って猫と犬の振る舞いを表現する例を示しています。

class Animal
  def initialize(name)
    @name = name
  end

  def say_hello
    puts "こんにちは、#{@name}です"
  end
end

class Cat < Animal
  def say_hello
    super
    puts "にゃーん"
  end
end

class Dog < Animal
  def say_hello
    super
    puts "わんわん"
  end
end

cat = Cat.new('たま')
dog = Dog.new('ポチ')

cat.say_hello
dog.say_hello

ここでは、AnimalクラスからCatクラスとDogクラスを継承しています。

継承するには<を使います。

そして、CatクラスとDogクラスではsay_helloメソッドをオーバーライド(上書き)しています。

オーバーライドしたsay_helloメソッドでは、まずsuperを呼び出して親クラスのsay_helloメソッドを実行し、その後に猫と犬の鳴き声を出力しています。

このようにすることで、共通の振る舞いは親クラスで定義し、それぞれの特性は子クラスで定義することができます。

最後に、CatクラスとDogクラスのインスタンスを作成し、それぞれのsay_helloメソッドを呼び出しています。

ここでのポイントは、どちらのインスタンスもsay_helloという同じメソッドを呼び出しているにも関わらず、それぞれ異なる振る舞いをすることです。

これがポリモーフィズムの一例です。

このコードを実行すると、次のような結果が得られます。

こんにちは、たまです
にゃーん
こんにちは、ポチです
わんわん

このように、継承とポリモーフィズムを使うことで、一部の振る舞いを共通化しつつも、それぞれのオブジェクト特有の振る舞いを表現することができます。

●Rubyでオブジェクト指向を活かすためのコーディングテクニック

Rubyでのオブジェクト指向プログラミングを活かすための有効なコーディングテクニックについて説明します。

ここでは、DRY原則とリファクタリングの二つを取り上げます。

○DRY原則とリファクタリング

DRY原則とは、”Don’t Repeat Yourself”の頭文字をとったもので、”同じことを繰り返さない”というプログラミングの原則を指します。

これはコードの重複を避け、保守性を高めるための重要な考え方です。

重複したコードはバグの元になりやすく、また改修の手間も増えるため、可能な限り避けるべきです。

一方、リファクタリングとは、プログラムの振る舞いを変えずに内部の構造を改善することを指します。

リファクタリングによってコードは読みやすくなり、保守や拡張も容易になります。

それでは、DRY原則に基づいたコードの書き方とリファクタリングの例を見てみましょう。

○サンプルコード4:DRY原則に基づいたコードの書き方

このサンプルコードでは、Rubyのオブジェクト指向プログラミングを用いて、DRY原則に従ったコードの書き方を紹介します。

この例では、異なるクラスに同じ処理を書かずに、共通の処理を親クラスにまとめる方法を示します。

class Vehicle
  def initialize(name)
    @name = name
  end

  def introduce
    puts "#{@name}です"
  end
end

class Car < Vehicle
end

class Bike < Vehicle
end

car = Car.new('フェラーリ')
bike = Bike.new('ヤマハ')

car.introduce
bike.introduce

このコードでは、Vehicleクラスという親クラスを作成し、その子クラスとしてCarクラスとBikeクラスを定義しています。

そして、introduceメソッドという共通の処理を親クラスであるVehicleクラスに定義し、その子クラスから呼び出しています。

このコードを実行すると、次のような結果が得られます。

フェラーリです
ヤマハです

このように、DRY原則に基づいてコードを書くことで、同じ処理を複数の場所に書かずに済みます。

これにより、コードの見通しがよくなり、バグを減らし、保守性を高めることができます。

次に、リファクタリングの例を見てみましょう。

○サンプルコード5:リファクタリングの例

このサンプルコードでは、Rubyのオブジェクト指向プログラミングを用いて、リファクタリングの一例を示します。

この例では、複雑な条件分岐をメソッドに分割することで、コードの可読性と保守性を向上させます。

class User
  def initialize(age, driver_license)
    @age = age
    @driver_license = driver_license
  end

  def can_drive?
    old_enough? && has_license?
  end

  private

  def old_enough?
    @age >= 18
  end

  def has_license?
    @driver_license
  end
end

user = User.new(20, true)
puts user.can_drive?

このコードでは、Userクラス内にcan_drive?メソッドを定義しています。

このメソッドは、ユーザが車を運転できるかどうかを判定します。

判定は年齢と運転免許の有無、これら2つの条件から行います。

しかし、これらの条件を直接can_drive?メソッド内に書くのではなく、それぞれの条件をold_enough?メソッドとhas_license?メソッドとして別々に定義しています。

そして、can_drive?メソッド内でこれらのメソッドを呼び出しています。

このコードを実行すると、次のような結果が得られます。

true

このように、複雑な条件分岐をメソッドに分割することで、各メソッドが何を判定しているのかが一目でわかり、コードの可読性が向上します。

また、各条件の判定を修正する場合も、対応するメソッドを修正するだけで済むため、保守性も向上します。

●注意点と対処法

オブジェクト指向プログラミングは強力なツールですが、正しく使わなければその利点を最大限に活かすことは難しくなります。

ここでは、Rubyのオブジェクト指向プログラミングにおける一般的な落とし穴と、それらをどのように避けるかについて説明します。

○Rubyにおけるオブジェクト指向の落とし穴

Rubyのオブジェクト指向プログラミングにおける一つの落とし穴は、「スーパークラスで定義したメソッドのオーバーライド」です。

スーパークラスのメソッドをサブクラスで再定義(オーバーライド)すると、予期しない挙動を引き起こすことがあります。

特に、サブクラスがスーパークラスのメソッドを知らずにオーバーライドすると、そのメソッドが意図しない動作をする可能性があります。

これを避けるための対策は、スーパークラスのメソッドをオーバーライドするときは常にsuperを使って元のメソッドを呼び出すことです。

これにより、スーパークラスの振る舞いを保持しつつ、サブクラスで追加の動作を定義することができます。

次に、「オブジェクトの状態管理」があります。

Rubyのオブジェクト指向プログラミングでは、オブジェクトの状態を管理するためにインスタンス変数を用いることが一般的です。

しかし、インスタンス変数の扱いに注意が必要で、これが不適切に管理されると、予期しない挙動やバグを引き起こす可能性があります。

これを避けるための対策は、可能な限りオブジェクトの状態を少なくすること、つまり、必要なインスタンス変数を最小限に保つことです。

また、オブジェクトの状態を変更するメソッドは慎重に管理し、他のメソッドから影響を受けないようにすることも重要です。

○オブジェクト指向の正しい理解と活用法

オブジェクト指向プログラミングを効果的に利用するためには、オブジェクト指向の主要な原則を理解し、それに基づいてコードを設計することが重要です。

その原則とは、「カプセル化」、「継承」、「ポリモーフィズム」の三つです。

「カプセル化」は、データとそのデータを操作するメソッドを一つの「オブジェクト」にまとめることで、外部から直接アクセスされるのを防ぎます。

「継承」は、既存のクラス(スーパークラス)のプロパティやメソッドを新たなクラス(サブクラス)が受け継ぐことで、コードの再利用性を高めます。

「ポリモーフィズム」は、異なるクラスのオブジェクトが同じインターフェース(メソッド)を共有することで、オブジェクトのタイプに関わらず同じ動作をさせることができます。

これらの原則を理解し、それに基づいてコードを設計することで、Rubyのオブジェクト指向プログラミングを効果的に活用することができます。

これからも、オブジェクト指向の理念を持ち、コードの可読性と再利用性を高め、保守性を向上させ、バグを減らすための方法を探求し続けてください。

そして、その結果をもとに、より洗練されたオブジェクト指向の設計と実装を行うことで、Rubyプログラミングのスキルを磨いていくことをお勧めします。

まとめ

この記事では、Rubyにおけるオブジェクト指向の基本から応用までを紹介しました。

Rubyのオブジェクト指向を理解することで、コードをより効率的に、かつ直感的に書くことができます。

今後は、これらの概念を意識しながらRubyのコードを書いてみてください。

そして、自分自身のプログラミングスキルを磨くために、様々なプロジェクトや課題に挑戦してみてください。