教科の平均点を出すアプリケーションをクラスを使って書き換えてみたいです。
解決済
回答 1
投稿
- 評価
- クリップ 1
- VIEW 3,138

退会済みユーザー
現在はインスタンスメソッドを使ったコードを構成しました。
このコードをクラスとインスタンスを使って書き換えたいです。
自分でも考えてみましたが手の付け所がわからず、よりよいコードを知りたいので、みなさんの考えを教えてほしく投稿いたしました。
よろしくお願いいたします。
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ページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
+2
単純に答えを書いてしまうよりちゃんと理解した方が良いと思ったのでちょっとだけ長くなります。
クラス化する、という意味を把握すると理解しやすくなるかと思います。クラス化するという事はそのクラスが内包するデータと一連の処理が、異なる状態で個別に保持され処理される事を意味します。
このケースであれば、何が個別であるべきかと考えると入力中の成績がそれにあたるかと思います。
この例は画面から入力する形式です。なので入力操作が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 にしてしまいがちですが、上記の様にクラスとして保持する事で、今後メソッドを増やす際に扱いやすくなります。
例えば、生徒を合格にしたり失格にするメソッドを簡単に追加できる様になります。
クラス化とはどんなデータや処理の固まりを纏めるかを予め意識しておくと実装しやすくなります。上記で私が書いたコードが正解という訳ではないので、ご自身で理解して「何を保持して」「どう処理したい」を検討して答えを出した方が良いかと思います。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.13%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2017/01/04 23:26
Classの中にinput_scoreは環境依存してしまうからNGの場合があるということ、初めて知ることなので大変参考になります。
show_all_scoreでハッシュを引数にして渡していましたが、クラス変数を用いて自己代入演算子で@@scoresをeachで分解していて、こういう方法もあるのかと驚いております。
クラス化するときは、そうするに値する処理の塊があるときに実装するということで、今後はコードを無造作に書き始めるのではなく、あらかじめ設計して書いていきたいとおもいます!
ありがとうございました!