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

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

ただいまの
回答率

90.46%

  • Ruby

    7989questions

    Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

教科の平均点を出すアプリケーションをクラスを使って書き換えてみたいです。

解決済

回答 1

投稿

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

soony

score 27

現在はインスタンスメソッドを使ったコードを構成しました。
このコードをクラスとインスタンスを使って書き換えたいです。
自分でも考えてみましたが手の付け所がわからず、よりよいコードを知りたいので、みなさんの考えを教えてほしく投稿いたしました。

よろしくお願いいたします。

def input_score
  score = {}
  puts "教科を入力してね"
  score[:subject] = gets.chomp
  puts "得点を入力してね"
  score[:score] = gets.to_i

  return score
end

def show_all_score(a_scores)
  sum = 0
  line = "-------------------------"
  puts line

  a_scores = a_scores.sort{|a, b| b[:score] <=> a[:score] }
  a_scores.each do |score|
    puts "#{score[:subject]} : #{score[:score]}点"
    sum = sum + score[:score]
  end

  puts line
  puts "平均得点は : #{sum/a_scores.count}点です!"
end


scores = []

while true do
  puts "テストの平均点を算出してみよう"
  puts "得点を入力する! | する[0] しない[1]"
  input = gets.to_i

  if input == 0
    scores << input_score
  elsif input == 1
    show_all_score(scores)
    exit
  end
end
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

+1

単純に答えを書いてしまうよりちゃんと理解した方が良いと思ったのでちょっとだけ長くなります。

クラス化する、という意味を把握すると理解しやすくなるかと思います。クラス化するという事はそのクラスが内包するデータと一連の処理が、異なる状態で個別に保持され処理される事を意味します。
このケースであれば、何が個別であるべきかと考えると入力中の成績がそれにあたるかと思います。

この例は画面から入力する形式です。なので入力操作がPCに対して1つしか存在しえない事になります。なおかつこの例は1人の成績を入力するプログラムです。
つまりクラス化の題材としてはあまり良く無いのですが、敢えてこれをクラス化するならば以下の様になるかと思います。

def input_score
  score = {}
  puts "教科を入力してね"
  score[:subject] = gets.chomp
  puts "得点を入力してね"
  score[:score] = gets.to_i

  return score
end


class Student
  @@scores = []

  def show_all_score
    sum = 0
    line = "-------------------------"
    puts line

    @@scores.sort{|a, b| b[:score] <=> a[:score] }.each do |score|
      puts "#{score[:subject]} : #{score[:score]}点"
      sum = sum + score[:score]
    end

    puts line
    if @@scores.count > 0
      puts "平均得点は : #{sum/@@scores.size}点です!"
    end
  end

  def input
    puts "テストの平均点を算出してみよう"
    puts "得点を入力する! | する[0] しない[1]"
    input = gets.to_i

    if input == 0
      @@scores << input_score
    elsif input == 1
      self.show_all_score
      break
    end
  end
end

s = Student.new
while true do
  s.input
end

Student は個別に1人の成績を保持するクラスになりました。ここでなぜ input_score をメソッドにしなかったのかを考えてみて下さい。画面とのやりとりは基本同時に1つしか実行しえませんよね。そういった処理をメソッドにしてしまうと必要のない環境依存(画面入力という依存)に縛られます。そうさせない為にはクラスから切り離すといった実装にする事が多いです。(ただし場合によります)
さて、この例は1人の成績を続けて入力するプログラムですが、例えば入力のシーケンスを以下に変更すると考えてみて下さい。

  • 誰が
  • どの教科で
  • 何点だった

そうすると Student の構造は以下の様になると連想できますよね。

class Student
  @@name = ''
  @@scores = []
  def initialize(name)
    @@name = name
  end
end

そして入力操作も input_score に移る前に名前を入力させる形式が良いと連想できますよね。この Student を生徒ID や生徒名をキーにした Hash とし、値として Student を格納すれば、学級内の成績を管理できる事が連想できるかと思います。

students = Hash.new
while true do
  name = input_name
  students[name] ||= Student.new(name)
  students[name].input
end

これをオリジナルのコードの延長線上で実装するならば scores (配列)を値に持つ Hash にしてしまいがちですが、上記の様にクラスとして保持する事で、今後メソッドを増やす際に扱いやすくなります。
例えば、生徒を合格にしたり失格にするメソッドを簡単に追加できる様になります。

クラス化とはどんなデータや処理の固まりを纏めるかを予め意識しておくと実装しやすくなります。上記で私が書いたコードが正解という訳ではないので、ご自身で理解して「何を保持して」「どう処理したい」を検討して答えを出した方が良いかと思います。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/01/04 23:26

    ご回答いただきましてありがとうございます。
    Classの中にinput_scoreは環境依存してしまうからNGの場合があるということ、初めて知ることなので大変参考になります。
    show_all_scoreでハッシュを引数にして渡していましたが、クラス変数を用いて自己代入演算子で@@scoresをeachで分解していて、こういう方法もあるのかと驚いております。
    クラス化するときは、そうするに値する処理の塊があるときに実装するということで、今後はコードを無造作に書き始めるのではなく、あらかじめ設計して書いていきたいとおもいます!

    ありがとうございました!

    キャンセル

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

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

関連した質問

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

  • Ruby

    7989questions

    Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。