質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.07%

【Ruby】オブジェクト指向で、もうちょいセンスのあるコードに書き換えたい

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 297

kazuki0714

score 28

テーマは、「フェラーリは車高を40cmリフトアップしたら速度が20%遅くなる」ということをコードにしたいです。
前提条件として「リフトダウンはリフトアップしてからじゃないとできない」ということを ferrari.rb に定義しました。(リフトアップ/ダウンはフェラーリだけしかできないので)
定義の仕方がいまいち弱いというか、これだと定義しなくても putsの中の計算式でなんとかなるくね?
と思ってしまい、なんか違うなぁと。

直したい箇所は ferrari.rb のdef lift_down の「時速」と「車高」を def lift_up で計算された数値から計算されるようなコードにしたいのですがどうすればいいでしょうか?

lift_upで計算した数値を基準に元に戻そうと#{car.lift_up.speed /0.8}km とかにしたらエラーが出るし、どうすればいいか悩んでいまして、アドバイスお願いいたします。

# main.rb
require_relative 'car'
require_relative 'ferrari'
require_relative 'honda'
require_relative 'nissan'

honda = Honda.new
honda.output_information(honda)

nissan = Nissan.new
nissan.output_information(nissan)

ferrari = Ferrari.new
ferrari.output_information(ferrari)

ferrari.lift_up(ferrari)
ferrari.lift_down(ferrari)
#car.rb (parent class)
class Car
  attr_accessor :type, :capasity, :price, :speed, :height

  def equipment
    %w[アクセル ブレーキ]
  end

  def output_information(car)
    puts '---------------------------------'
    puts "車種: #{car.type}"
    puts "定員: #{car.capasity}"
    puts "価格: #{car.price}円"
    puts "時速: #{car.speed}km"
    puts "車高: #{car.height}cm"
    puts "装備: #{car.equipment.join(', ')}"
  end
end
# ferrari.rb
class Ferrari < Car
  def initialize 
    @type = 'フェラーリ'
    @capasity = 2
    @price = 2_000_000_0
    @speed = 100
    @height = 100
  end

  def lift_up(car)
    @is_lift = true
    puts '----フェラーリ(リフトアップ)----'
    puts "車種: #{car.type}"
    puts "定員: #{car.capasity}"
    puts "価格: #{car.price}円"
    puts "時速: #{car.speed* 0.8}km"
    puts "車高: #{car.height+ 40}cm"
    puts "装備: #{car.equipment.join(', ')}"
  end

  def  lift_down(car)
    return unless @is_lift
    @is_lift = false
    puts '----フェラーリ(リフトダウン)----'
    puts "車種: #{car.type}"
    puts "定員: #{car.capasity}"
    puts "価格: #{car.price}円"
    puts "時速: #{(car.speed* 0.8)/ 0.8}km" #ここをリフトアップした数値を基準に元の数値に戻したい
    puts "車高: #{(car.height+ 40) - 40}cm" #ここをリフトアップした数値を基準に元の数値に戻したい
    puts "装備: #{car.equipment.join(', ')}"
  end
end
# honda.rb
class Honda < Car
  def initialize
    @type = 'ホンダ'
    @capasity = 8
    @price = 100_000_0
    @speed = 10
    @height = 100
  end
end
# nissan.rb
class Nissan < Car
  def initialize
    @type = 'ニッサン'
    @capasity = 5
    @price = 50_000_0
    @speed = 10
    @height = 100
  end
end

下記は出力した時のスクショです。
イメージ説明

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

#car.rb (parent class)
class Car
  # capasity -> capacity
  attr_accessor :type, :capacity, :price, :speed, :height

  def equipment
    %w[アクセル ブレーキ]
  end

  def output_information
    puts '---------------------------------'
    puts "車種: #{type}"
    puts "定員: #{capacity}"
    puts "価格: #{price}円"
    puts "時速: #{speed}km"
    puts "車高: #{height}cm"
    puts "装備: #{equipment.join(', ')}"
  end

  def initialize(type: '(車種)', capacity: 1, price: 0, speed: 10, height: 100)
    @type = type
    @capacity = capacity
    @price = price
    @speed = speed
    @height = height
  end
end


# ferrari.rb
class Ferrari < Car
  def initialize
    # 親(Car)のinitializeを呼び出す
    # 親クラスのインスタンス変数を直接操作するのは、親クラスの仕様変更に弱い
    super(
      type: 'フェラーリ', capacity: 2,
      price: 2_000_000_0, speed: 100
    )
    output_information
  end

  def lift_up
    @is_lift = true
    # selfの状態を変更し
    self.type = 'フェラーリ(リフトアップ)'
    self.speed *= 0.8
    self.height += 40
    # 出力は親クラスのメソッドに任せる
    output_information
  end

  def  lift_down
    # 何もせずreturnするだけよりは、呼び出し元に対して例外を返した方が親切
    raise "リフトアップしていない車はリフトダウンできません" unless @is_lift
    @is_lift = false
    self.type = 'フェラーリ(リフトダウン)'
    self.speed /= 0.8
    self.height -= 40
    output_information
  end
end

ferrari = Ferrari.new
ferrari.output_information
ferrari.lift_up
ferrari.lift_down

全体的に、carを引数に取る必要はなく(必要ならば)selfを使います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/07/31 11:23

    output_informationを違うメソッドで定義するほうがいいということでしょうか?
    (例えば `lift_up_output` のようなメソッドで)

    キャンセル

  • 2019/07/31 11:35

    lift_upは変更のみで、表示したいのならば各々output_informationを実行する感じですね

    ただ、記述量が単純に倍になってめんどくさいですし
    変更を実行し、結果を表示するための整備工場的なクラスを間に挟んで
    利用者はそこに車を持ち込んで注文する・・・てのが個人的にはスッキリするかな と思います。

    自分だけしか開発に関わってなく利用者も自分だけという小規模ならば、あえて無視する程度の問題です

    キャンセル

  • 2019/07/31 11:43

    なるほどですね、ありがとうございます!
    勉強用に自分1人で書いてたのでそこまで意識が回ってませんでした(>_<)

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.07%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る