【Ruby】オブジェクト指向とは

# はじめに
こんにちは、Ruby絶賛勉強中で本日から「たのしいRuby」を読み始めました。
その中でRubyはオブジェクト指向言語であると書いてありました。
オブジェクト指向って聞いたことあるけど、実際何なのか？と思って気になったので調べた内容を記事にまとめてみました。

# オブジェクト指向とは
オブジェクト指向プログラミングとはデータとその操作を「オブジェクト」という単位でまとめる考え方に基づいています。
オブジェクトは、現実世界のモノや概念をプログラム内で再現し、データ（属性）とそれに対する操作（メソッド）を一つのまとまりとして扱います。
オブジェクト指向プログラミング以外には手続き型言語というものがあり、C言語やFortranがあります
もともとオブジェクト指向を知っている方でないとこの説明を聞いて、なるほどとはならないと思いますので具体例を挙げて説明していきたいと思います

例えば、私たちが普段使っている「スマートフォン」をプログラムで表現したいとしましょう。
現実世界のスマートフォンの特徴をまとめるとすると
* メーカー（例：Apple、Samsung）
* モデル（例：iPhone 14、Galaxy S23）
* 色（例：黒、白）
* ストレージ容量（例：128GB、256GB）
* バッテリー残量
のようにまとめることができます。スマートフォンの動作についてもまとめると
* 電話をかける
* 写真を撮る
* インターネットに接続する
これをプログラムで再現すると、「スマートフォン」というオブジェクトは、その特徴（属性）と動作（メソッド）を持つことになります。

```ruby:smartphone.rb
class Smartphone
  attr_accessor :manufacturer, :model, :color, :storage, :battery

  def initialize(manufacturer, model, color, storage)
    @manufacturer = manufacturer
    @model = model
    @color = color
    @storage = storage
    @battery = 100  # 初期バッテリーは100%とする
  end

  def make_call(number)
    puts "Calling #{number}..."
    @battery -= 5  # 通話でバッテリーを消耗する
  end

  def take_photo
    puts "Taking a photo..."
    @battery -= 10  # 写真を撮るとバッテリーを消耗する
  end
end

# スマートフォンのオブジェクトを作成
my_phone = Smartphone.new("Apple", "iPhone 14", "Black", "256GB")

# スマートフォンで電話をかける
my_phone.make_call("123-456-7890")
# => Calling 123-456-7890...

# スマートフォンで写真を撮る
my_phone.take_photo
# => Taking a photo...
```
この例では、「スマートフォン」というオブジェクトをプログラム内で作成しました。
`my_phone`というオブジェクトは、AppleのiPhone 14で、色が黒、容量が256GB、バッテリーが100%のスマートフォンです。
そして、このオブジェクトに対して「電話をかける」や「写真を撮る」といった動作を実行することができます。

このように、「現実のスマートフォン」が持っている特性や動作を、プログラム内の「オブジェクト」に再現しているのが、オブジェクト指向の基本的な考え方です。

# オブジェクト指向の特徴
ここまでオブジェクト指向について具体例を挙げて説明しましたが、特徴について記述していきます
* カプセル化 
データ（プロパティ）とその操作（メソッド）をオブジェクトの内部に隠蔽し、外部から直接アクセスできないようにします。
これにより、データの不正な操作を防ぎ、オブジェクトの内部実装を変更しても外部に影響を与えにくくなります。
これも具体例をみながら理解しましょう
カプセル化を理解するために、銀行口座の例を使って説明します。
銀行口座には残高（`balance`）があり、ユーザーはその残高に直接アクセスして変更するべきではありません。
代わりに、ユーザーはお金を預けたり引き出したりするために、専用のメソッド（`deposit`や`withdraw`）を使います。
```Ruby:bank.rb
class BankAccount
  def initialize(owner, initial_balance)
    @owner = owner
    @balance = initial_balance
  end

  # 公開されたメソッド（ユーザーが操作できるメソッド）
  def deposit(amount)
    if amount > 0
      @balance += amount
      puts "#{amount} has been deposited. New balance: #{@balance}"
    else
      puts "Deposit amount must be positive."
    end
  end

  def withdraw(amount)
    if amount > 0 && amount <= @balance
      @balance -= amount
      puts "#{amount} has been withdrawn. New balance: #{@balance}"
    else
      puts "Insufficient funds or invalid amount."
    end
  end

  # 残高を確認するメソッド
  def check_balance
    puts "Current balance: #{@balance}"
  end

  private
  # プライベート変数やメソッド（外部から直接アクセスできない）
  attr_reader :balance
end

# 銀行口座を作成
account = BankAccount.new("John Doe", 1000)

# お金を預ける
account.deposit(500)  # => 500 has been deposited. New balance: 1500

# お金を引き出す
account.withdraw(200)  # => 200 has been withdrawn. New balance: 1300

# 残高を確認する
account.check_balance  # => Current balance: 1300

# プライベート変数への直接アクセスは禁止される
# puts account.balance  # => エラーになる（外部から直接アクセス不可）
```
この例では、`@balance`（残高）はプライベート変数です。
外部から直接アクセスできないようにしています。
`attr_reader :balance`で読み取り専用のプライベートメソッドにしており、クラス外部からは参照できません。


* 継承
既存のクラス（親クラス）から新しいクラス（子クラス）を作成し、親クラスのプロパティやメソッドを引き継ぐ仕組みです。これにより、コードの再利用性が向上し、新たなクラスを簡単に作成できます。
これについては以前記事を書いたので読んでいただけたら嬉しいです

https://qiita.com/Taira0222/items/0dbe2c3c75fccb3de824


* ポリモーフィズム
同じメソッド名や操作が、異なるオブジェクトで異なる動作をすることが可能です。
これにより、コードの柔軟性が増し、異なる型のオブジェクトでも同じインターフェースで操作ができるようになります。
これだけではわかりずらいので具体例を見てみましょう

例えば、動物（`Animal`）を例にしてみましょう。猫（`Cat`）や犬（`Dog`）はそれぞれ違った行動をしますが、どちらも「鳴く」という動作を持っています。
この「鳴く」動作（`speak`メソッド）は、猫と犬で違った動きをします。
```ruby:polymorphism.rb
class Animal
  def speak
    puts "Some generic animal sound"
  end
end

class Cat < Animal
  def speak
    puts "Meow"
  end
end

class Dog < Animal
  def speak
    puts "Woof"
  end
end

# 異なる動物オブジェクトを作成
cat = Cat.new
dog = Dog.new

# 同じメソッド名を使っても、オブジェクトに応じて動作が異なる（ポリモーフィズム）
cat.speak  # => Meow
dog.speak  # => Woof
```
この例では、`Cat`と`Dog`のオブジェクトに対して同じ`speak`メソッドを呼び出していますが、クラスによって異なる動作をします。
これがポリモーフィズムです

* 抽象化
これは`Linux`を勉強している際に勉強しましたが、抽象化とは複雑なシステムを単純なモデルに落とし込むことです。
必要な情報だけを公開し、不要な詳細は隠すことで、ユーザーは複雑なシステムの内部動作を理解せずに利用できます。
抽象化の例でいうと、Windowsでフォルダーを右クリック、新規作成するのもCLIの抽象化によりGUIで操作できるようになっています。
オブジェクト指向も同様で、複雑な処理を抽象化によってコードを書く我々は簡単にコードを書くことが可能です。


# オブジェクト指向のメリット、デメリット
ここまでで、オブジェクト指向についてや、特徴を説明してきましたがここではメリットデメリットを説明していきたいと思います
* 再利用性の向上
クラスを作成すれば、それを基に複数のオブジェクトを簡単に作成できるため、コードの再利用がしやすくなります。
例えば、異なる車を何度も作ることが可能です。`Ruby`やほかのオブジェクト指向プログラミングを勉強した方ならイメージしやすいのではないでしょうか
* 保守性の向上
オブジェクト指向のコードは、データとその操作が一体となっているため、変更や修正が容易です。
ある部分を修正しても、他の部分に影響を与えにくいです。
* 柔軟性と拡張性
継承やポリモーフィズムにより、新しい機能を追加したり、既存のコードを拡張したりするのが簡単です。
大規模なアプリケーションに向いています。
* 直観的な操作
オブジェクト指向は、現実世界のモノや概念をオブジェクトとしてモデル化するため、開発者にとって直感的で理解しやすい設計が可能です。
* セキュリティ面
カプセル化により、クラスの内部データを外部から保護することもできるためセキュリティ面が高いといえます。


一方で当然デメリットも存在します
* オーバーヘッドが増える
小さなプログラムや単純なタスクに対しては、オブジェクト指向の設計は過剰になることがあります。
構造を考える手間が増え、必要以上に複雑になる場合があります。
* 学習コストが高い
オブジェクト指向の概念（カプセル化、継承、ポリモーフィズムなど）を理解するには時間がかかる場合があります。
特に、初心者にとっては習得に苦労することがあるかもしれません。
* パフォーマンスの問題
オブジェクト指向は、特定の操作やメモリの使用において手続き型プログラムに比べてパフォーマンスが劣ることがあります。
多くのオブジェクトやメソッド呼び出しが発生する場合、効率が低下することがあります。

# まとめ
エンジニアになるためには最低限説明できないといけないと聞いてはいましたが、こうしてまとめるのは初めてでした。
Rubyもオブジェクト指向で、ポートフォリオではシステムみたいな比較的大きめのものを作ろうと考えているので適していると感じました。
この記事をみてオブジェクト指向の理解が深まれば幸いです。