はじめに
Railsを勉強していると、次のようなコードがよく登場します。
company = Company.find(1)
company.name
company.save
最初は、
-
Companyとcompanyは何が違う? - オブジェクトって結局何?
- なぜ
company.nameやcompany.saveと書ける? - オブジェクト指向は実務で何の役に立つ?
といった疑問がありました。
この記事では、AIに質問しながら理解したオブジェクト指向の基本を、Railsの具体例と一緒に整理します。
1. オブジェクト指向とは?
一言でいうと
関連する「データ」と「処理」を、1つの「もの」としてまとめて設計する考え方
です。
例えばECサイトには、次のような「もの」があります。
- ユーザー
- 商品
- 注文
- 会社
オブジェクト指向では、これらをプログラム上でも役割ごとに分けて考えます。
ECサイト
│
├── User
│ ├── 名前
│ ├── メールアドレス
│ └── ユーザーに関する処理
│
├── Product
│ ├── 商品名
│ ├── 価格
│ ├── 在庫
│ └── 商品に関する処理
│
└── Order
├── 注文日時
├── 合計金額
└── 注文に関する処理
なぜオブジェクト指向が必要なのか?
小さなプログラムなら、変数やメソッドをバラバラに書いても管理できます。
しかし、実務のWebアプリでは、
ユーザー
会社
商品
注文
支払い
コメント
通知
権限
ログイン
...
のように、多くのデータや処理が登場します。
すべてをバラバラに管理すると、
- このデータは何に関係するのか
- この処理はどこに書けばいいのか
- このメソッドは何を操作しているのか
- 変更したときに他へ影響しないか
といったことが分かりにくくなります。
そこで、関連するものをまとめます。
Product
├── 商品データ
└── 商品に関する処理
User
├── ユーザーデータ
└── ユーザーに関する処理
Order
├── 注文データ
└── 注文に関する処理
つまりオブジェクト指向は、大きなプログラムを整理して、理解・変更しやすくするための考え方でもあります。
2. 基本的な使い方
クラスとオブジェクトの違い
まずは、この4つを押さえると理解しやすいです。
| 用語 | 意味 | 例 |
|---|---|---|
| クラス | オブジェクトを作るための設計図 | User |
| オブジェクト | クラスをもとに作られた実体 | user1 |
| 属性 | オブジェクトが持つデータ |
name, age
|
| メソッド | オブジェクトに対する処理 | introduce |
Rubyでクラスを作る
ユーザーを表すUserクラスを作ってみます。
class User
def initialize(name, age)
@name = name
@age = age
end
def introduce
"#{@name}です。#{@age}歳です。"
end
end
このクラスを図にすると、次のような構造です。
Userクラス
│
├── データ
│ ├── @name
│ └── @age
│
└── 処理
└── introduce
オブジェクトを作る
次に、Userクラスから実際のオブジェクトを作ります。
user1 = User.new("田中", 22)
user2 = User.new("佐藤", 25)
User.newによって、Userクラスをもとにしたオブジェクトが作られます。
Userクラス
設計図
│
┌───────┴───────┐
↓ ↓
User.new User.new
↓ ↓
user1 user2
┌────────┐ ┌────────┐
│ 田中 │ │ 佐藤 │
│ 22歳 │ │ 25歳 │
└────────┘ └────────┘
同じUserクラスから作られていても、それぞれ別のデータを持つことができます。
メソッドを使う
先ほど、Userクラスにはintroduceというメソッドを定義しました。
def introduce
"#{@name}です。#{@age}歳です。"
end
そのため、
user1.introduce
とすると、
田中です。22歳です。
という結果になります。
イメージとしては、
user1
│
│ .introduce
↓
「自己紹介して」
↓
田中です。22歳です。
と考えると分かりやすいです。
3. Railsではどう使われている?
ここからは、Railsのコードとオブジェクト指向をつなげて考えます。
例えば、DBにcompaniesテーブルがあるとします。
| id | name | address |
|---|---|---|
| 1 | サンプル株式会社 | 東京 |
| 2 | テスト株式会社 | 横浜 |
Railsでは、これに対応するモデルを次のように定義します。
class Company < ApplicationRecord
end
このCompanyはクラスです。
Company.find(1)とは?
次のコードを実行してみます。
company = Company.find(1)
Company.find(1)は簡単にいうと、
companiesテーブルからid = 1のデータを取得する
処理です。
流れを図にすると、次のようになります。
companiesテーブル
┌────┬──────────────────┬─────────┐
│ id │ name │ address │
├────┼──────────────────┼─────────┤
│ 1 │ サンプル株式会社 │ 東京 │
└────┴──────────────────┴─────────┘
│
│ Company.find(1)
↓
Companyオブジェクト
│
│ companyに代入
↓
company
つまり、
company = Company.find(1)
は、
DBから取得したCompanyオブジェクトを、
companyという変数に入れている
と考えられます。
Companyとcompanyの違い
ここは特に混乱しやすい部分です。
company = Company.find(1)
それぞれの役割を整理すると、次のようになります。
| コード | 意味 |
|---|---|
Company |
クラス |
Company.find(1) |
id = 1のCompanyオブジェクトを取得 |
company |
取得したオブジェクトを入れる変数 |
図にすると、
Company
↑
クラス
│
│ .find(1)
↓
Companyオブジェクト
│
│ 代入
↓
company
↑
変数
となります。
属性を取得する
companyにはCompanyオブジェクトが入っているため、
company.name
と書くことができます。
結果は、
サンプル株式会社
です。
同様に、
company.address
なら、
東京
を取得できます。
メソッドを実行する
Railsでは、次のようなコードもよく見かけます。
company.save
company.destroy
例えば、
company = Company.find(1)
company.name = "新しい会社名"
company.save
とすると、companyのnameを変更し、その内容をDBに保存できます。
イメージすると、
company
│
├── データ
│ ├── id
│ ├── name
│ └── address
│
└── 処理
├── save
└── destroy
という関係です。
自分でメソッドを作ることもできる
Railsのモデルには、自分でメソッドを追加することもできます。
class Company < ApplicationRecord
def display_name
"#{name}(#{address})"
end
end
すると、
company = Company.find(1)
company.display_name
と書くことができます。
結果は、
サンプル株式会社(東京)
となります。
ここでは、
Company
│
├── データ
│ ├── name
│ └── address
│
└── 処理
└── display_name
のように、会社に関するデータと処理がCompanyにまとまっていることが分かります。
これが、
関連するデータと、そのデータに関係する処理を1つにまとめる
というオブジェクト指向の考え方につながります。
ここまでのまとめ
最後に、Railsのコードを使って関係を整理すると次のようになります。
Company
│
│ クラス
↓
Company.find(1)
│
│ オブジェクトを取得
↓
company
│
│ 取得したオブジェクトを入れる変数
│
├── company.name
│ └── データを取得
│
├── company.save
│ └── 保存
│
└── company.destroy
└── 削除
オブジェクト指向という言葉だけを見ると難しく感じますが、Railsで普段使うコードに置き換えると、
クラスをもとにオブジェクトを扱い、そのオブジェクトが持つデータや処理を呼び出している
という構造が見えてきます。