【Ruby】オブジェクト指向について基礎的なあれこれ

#はじめに
今後個人開発でもっと複雑なものや共同開発をしていく上でオブジェクト指向の理解が重要だと考え、勉強のアウトプットとして記事にしました。

**この記事でわかること**
　・オブジェクト指向の概要
　・三大要素
　・オブジェクト指向での設計のポイント

参考にしました→[オブジェクト指向でなぜ作るのか](https://www.amazon.co.jp/%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E6%8C%87%E5%90%91%E3%81%A7%E3%81%AA%E3%81%9C%E3%81%A4%E3%81%8F%E3%82%8B%E3%81%AE%E3%81%8B-%E7%AC%AC2%E7%89%88-%E5%B9%B3%E6%BE%A4-%E7%AB%A0/dp/4822284654)

#オブジェクト指向の概要
オブジェクト指向という言葉自体はゼロックス社パロアルト研究所の計算機科学者アラン・ケイが70年代生み出した言葉です。その後、自由で曖昧な定義のまま発展を続けたので、どんなものかを説明するのが難しいです。

しかし、ざっくり説明すると**ソフトウエアの保守や再利用をしやすくすることを目的とした技術**です。個々の部品により強く着目し、部品の独立性を高め、それらを組み上げてシステム全体の機能を実現するという考え方にもとづきます。
オブジェクト指向プログラミング言語はと**OOP**（ObjectOrientedProgramminglanguage）と呼ばれます。

**【代表的なOOP】**
Simula67、Smalltalk、C++、Python、Java、Ruby、JavaScript..などなど

また、オブジェクト指向には**三大要素**があります。

- **クラス（カプセル化）**
- **ポリモーフィズム**
- **継承**

また、オブジェクト指向には、抽象的な**「汎用の整理術」**と、具体的な**「プログラミング技術」**という2つの側面があります。

# 三大要素

##クラス（カプセル化）
「分類」「種類」といった「同種のものの集まり」と言った意味。関連性の強い**メソッド**と**インスタンス変数**を1つにまとめて粒度の大きいソフトウエア部品を作る仕組みです。 
この仕組みの特徴は**「まとめて、隠して、たくさん作る」**ことです。

####メソッドとは？
プログラムの一連の処理をまとめたパッケージのようなものです。言語によっては関数と呼ばれます。

####インスタンスとは？
クラスをもとに生成されたオブジェクトの実体です。

####１．まとめる
結びつきの強い（複数の）メソッドと（複数の）インスタンス変数を１つのクラスに「まとめる」ことができます。

![名称未設定ファイル.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687088/38827ce9-51f1-145e-60b8-21ed7e3c16d3.png)

これにより次のメリットが得られます。

**【利点】**

- 部品の数が減る。
- メソッドの名前づけが楽になる。
- メソッドが探しやすくなる。

####2．隠す
クラスに定義した変数とメソッドを、他のクラスから「隠す」ことができます。プログラムの保守性悪化の元凶となるグローバル変数を使わずにプログラムを書くことが可能です。
Rubyでは``private``を使用します。

####3．たくさん作る
いったんクラスとして定義すると、実行時にそこからいくつでもインスタンスを作ることができます。これにより、ファイル、文字列、顧客情報など、同種の情報を複数同時に扱う処理であっても、そのクラス内部のロジックをシンプルにできます。
Rubyではインスタンスメソッドを実行する際、下記の様にインスタンスを格納する変数名にピリオドをつけて、その後にメソッド名を書きます。

**インスタンスを格納する変数名．メソッド名（引数）**

**【まとめ】**

- サブルーチンと変数を「まとめる」
- クラスの内部だけで使う変数やサブルーチンを「隠す」
- １つのクラスからインスタンスを「たくさん作る」

##ポリモーフィズム
類似したクラスに対するメッセージの送り方を共通にする仕組み。また、相手が具体的にどのクラスのインスタンスであるかを意識せずにメッセージを送れる仕組みです。

##継承
継承は、クラス定義の共通部分を別クラスにまとめて、コードの重複を排除する仕組みです。
共通部分のクラスのことを**スーパークラス**と呼び、それを利用するクラスを**サブクラス**呼びます。

![スーパークラス.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687088/8f724aa4-e8f5-2c76-8e87-2e03522a3ff0.png)


##三大要素まとめ

|   | クラス | ポリモーフィズム | 継承 |
|:-:|:-:|:-:|:-:|
| 説明 | サブルーチンと変数をまとめてソフトウェア部品を作る | メソッドを呼び出す側を共通化する | 重複するクラス定義を共通化する |
| 目的 | 整理整頓 | 無駄を省く | 無駄を省く |

##  三大要素を使ったコーディング
Rubyを使用してオブジェクト指向を意識したコーディングをしていきます。

### クラス(カプセル化)

```Ruby:sample.rb
class Apple
 def initialize(quantity, price)
  @quantity = quantity
  @price = price
 end

 def buy
  puts "りんごを#{@quantity}個買い、#{calculation(@quantity, @price)}円でした。"
 end

 private

 def calculation(quantity, price)
  quantity * price
 end
end
```
Appleクラスを作成しました。
内容は下記図の通りとなります。

![名.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687088/6c390e4b-7a9e-316d-c38d-4d48f8354525.png)


irbを走らせ、インスタンスを生成しました。

```terminal
irb(main):002:0> apple1 = Apple.new(2, 300)
=> #<Apple:0x00007fc92c82be58 @quantity=2, @price=300>
irb(main):003:0> apple1.buy
りんごを2個買い、600円でした。
irb(main):002:0> apple2 = Apple.new(3, 300)
=> #<Apple:0x00007fc92c82be58 @quantity=2, @price=300>
irb(main):003:0> apple2.buy
りんごを3個買い、900円でした。
```

### ポリモーフィズム、継承

```Ruby:sample.rb

class Shopping
 def initialize(quantity, price)
  @quantity = quantity
  @price = price
 end

 def buy(product='')
  puts "#{product}を#{@quantity}個買い、#{calculation(@quantity, @price)}円でした。"
 end

 private

 def calculation(quantity, price)
  quantity * price
 end
end

class Apple < Shopping
  def buy(product='りんご')
    super
  end
end

class Orange < Shopping
  def buy(product='オレンジ')
    super
  end
end

```
下記図の通り、スーパークラスとしてShoppingクラスを作成しました。Apple、OrangeクラスにはShoppingクラスを**継承**させました。オーバーライドしているbuyメソッドを``super``でよびだしました（**ポリモーフィズム**）。

![名.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687088/e9f9ea0d-848d-a6d7-0339-abd398148076.png)

irbを走らせ、インスタンスを生成しました。

```terminal
irb(main):002:0> apple = Apple.new(2, 300)
=> #<Apple:0x00007fc92c82be58 @quantity=2, @price=300>
irb(main):003:0> apple.buy
りんごを2個買い、600円でした。
irb(main):002:0> orange = Orange.new(4 ,300)
=> #<Orange:0x00007fa55e96c5c0 @quantity=4, @price=300>
irb(main):003:0> orange.buy
オレンジを4個買い、1200円でした。
```

# オブジェクト指向での設計のポイントについて

### 重複を排除する
重複部分が多いと規模が大きくなり、コードが複雑になります。また、変更時の修正漏れが発生する場合があります。
ポリモーフィズムや継承の仕組みを利用し、なるべく重複を排除することが推奨されます。

### 部品の独立性を高める
複雑なシステムを部品ごとに分割することでサブシステムや部品の機能がハッキリするため、変更する場合の修正個所の特定が容易になります。また、独立した部品を別のシステムに再利用することも可能になります。
部品やサブシステムの独立性を高めるための考え方として、**「凝集度」**と**「結合度」**と呼ばれる2つの尺度があります。

**凝集度**
個々の部品の機能のまとまり度合いを評価する尺度です。この凝集度が「強い」ほど良い設計といえます。

**結合度**
部品間の結びつき度合いを評価する尺度です。この結合度は凝集度と反対に、「弱い」ほど良い設計といえます。

また、部品の独立性を高めるために具体的なコツとして下記3点があります。

- ひと言で表現する名前をつける

- 隠す仕組みを利用し秘密をたくさん作る

- 小さく作る

### 依存関係を循環させない
クラス同士の依存関係を循環させると再利用がしづらくなるため、循環しないような設計が必要になります。

# まとめ
 オブジェクト指向について学ぶために一冊本を読みましたが、メモリ、要件定義、モデリング、アジャイル開発など幅広いところまで波及しており、とてつもなく奥が深いと感じました。まだまだこれからも勉強していきたいと思います。