LoginSignup
1
1

More than 3 years have passed since last update.

オブジェクト指向とは何ぞや

Last updated at Posted at 2021-04-03

目的

テックキャンプのカリキュラムで「オブジェクト指向」について学んだので、その備忘録として残します。

概要

オブジェクト指向1とは、

アプリケーションを作成するときに、登場する役割ごとに分けて実装する方針

のことを言います。
RubyなどのWebアプリケーションに使用される言語の多くが、オブジェクト指向で実装する必要があります。

オブジェクト指向に沿うメリット

オブジェクト指向、つまりクラスに含まれる値や処理のまとまりを意識しながら、役割ごとにオブジェクトを分けて実装することで

  • 実装がしやすくなる
  • 後からコードを改編するときも、他のオブジェクトに影響しなくなる

といったメリットがあります。

オブジェクト指向に沿ったアプリケーションを考える

ここでは、以下のような
切符の券売機のアプリケーションの実装を例にして考えます。
券売機.gif

用意すべきクラスを考える

まずは、このアプリケーションについてどんなクラスを用意すべきかを考えます。

クラスを考える際は、「このアプリケーションにおいて、どのような処理が存在するのか」に着目します。

券売機アプリケーションには、以下のような処理が存在しそうです。

- 乗車券のデータを作成する
- ユーザーに販売している商品を見せる
- 購入したい乗車券を決める
- お金を投入する
- 投入金額からお釣りの計算をする(購入処理を行う)

これらの処理を、役割の種類ごとに分類し、それぞれをクラスとします。上記を分類すると、以下のような形になります。

クラス 意味 何をするのか
Ticket 販売する乗車券 登録された金額を実体のあるデータ(インスタンス)にする
TicketMachine 券売機 ユーザーに販売している乗車券を見せて、投入金額からお釣りの計算をする
User 購入する人 購入したい乗車券を決めて、お金を投入する



このアプリケーションには、このように少なくとも3つのクラスが必要ということになります。

「券売機のアプリケーションなので、券売機クラスだけ用意すればいいのでは?」と考えた方もいるかもしれません。
しかしその場合、「券売機が行うべきでないこと」も、券売機のクラスに含まれてしまうことになります。

例えば、TicketMachineクラスから見た場合、

  • 乗車券のデータを作成する
    • →券売機は、乗車券のデータそのものを作り出すことはできないのでは?
  • 購入したい乗車券を決める、お金を投入する
    • →これは券売機ではなく、購入者が行うことでは?

と言った疑問が生じます。

このようなアプリケーションになってしまうと、後からこのアプリケーションを修正する人は、
「なぜ券売機自身が投入金額を決めているの?」
と疑問を抱き、修正がしにくくなり、保守性が悪くなってしまいます。

それぞれのクラスには、明確な役割が1つだけ与えられている必要があります。これを単一責任の法則2と言います。

コードの記述

上記のクラスの情報をもとに、実際にコードを記述していきます。
(今回はコードの記述過程は省略します。)

今回は、クラス毎にファイルを分割して実装するため、
- application.rb(requireで他の3つのファイルを読み込む)
- user.rb
- ticket.rb
- ticket_machine.rb
の4つに分けてコードを記述します。


application.rb
require "./ticket"
require "./user"
require "./ticket_machine"



puts "乗車券を用意してください"
tickets = []
3.times do |i|
  puts "行き先を入力してください"
  ticket_name = gets.chomp
  puts "金額を入力してください"
  ticket_fee = gets.to_i
  tickets << Ticket.new(ticket_name,ticket_fee)
end

ticket_machine = TicketMachine.new(tickets)
ticket_machine.show_tickets
# 生成したインスタンスに対してshow_ticketsメソッドを適用

puts "投入金額を決めてください。"
money = gets.to_i
user = User.new(money)

ticket_machine.sell(user)
user.rb
# 投入金額を決める
class User
  def initialize(money)
    @money = money
  end

  def money
    @money
  end

  def choose_ticket
    gets.to_i
  end

end
ticket.rb
class Ticket
  def initialize(name,fee)
  @name = name
  @fee = fee
  end


  def name
    @name
  end
  # インスタンス変数の値のみを戻り値としたメソッドのことをゲッターと呼ぶ。

  def fee
   @fee
  end

end
ticket_machine.rb
class TicketMachine
  def initialize(tickets)
  @tickets = tickets
  end

  def tickets
    @tickets
  end

  def show_tickets
    puts "いらっしゃいませ。以下の商品を販売しています。"
    i = 0
    self.tickets.each do |ticket|
      # rubyのインスタンスメソッド内でのself記述は特別。ここではselfが書かれているインスタンスメソッドを適用したインスタンス自身が代入されていると考える。
      # 今回の場合、TicketMachineクラスのインスタンスが代入されている。
      puts "【#{i}#{ticket.name}: #{ticket.fee}円"
      i += 1
    end
  end

    # 選んだ商品をユーザーに対して販売する
    def sell(user)
      puts "商品を選んでください"
      chosen_ticket = user.choose_ticket
      change = user.money - self.tickets[chosen_ticket].fee
      if change >= 0
        puts "ご利用ありがとうございました。お釣りは#{change}円です。"
      else
        puts "投入金額が足りません。"
      end
    end

end



ここで、用意したクラスが券売機クラスのみだったと仮定すると、ticket_machine.rbに加えticket.rbuser.rbの内容が混在してしまいます。
そうなると、他の開発者と共同で開発を行なっている場合に、どこを修正すればいいのか非常に分かりづらくなってしまいます。

終わりに

ここまで読んで頂き、ありがとうございました。
コメント欄で改善点等、記事に関するご指摘を頂けると更に励みになりますので、よろしくお願いします。


  1. ここでいうオブジェクトとは、Rubyにおけるクラスやインスタンス、その他の値のことを意味する。文字列""や数値、配列[]やハッシュ{}など、これまで値と読んできたもの全てがオブジェクトである。 

  2. アプリケーションの設計を考える上で、必要となる決まりの1つ。上記の券売機アプリケーションでは、券売機・乗車券・購入者の役割が1つ程度になるよう分割されている。このように、「1つのクラスは1つの振る舞いしか持たない」という原則を意識しないと、他者からみた時に意図のわからないアプリケーションが完成してしまう。 

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1