2012年11月25日日曜日

Ruby - 新しいクラスの作成と既存クラスの変更(インスタンス変数とinitialize)

開発環境

『初めてのプログラミング 第2版』(Chris Pine 著、長尾 高弘 訳、オライリー・ジャパン、2010年、ISBN978-4-87311-469-9)の 13章(新しいクラスの作成と既存クラスの変更), 13.6(練習問題の続き)オレンジの木 を解いてみる。

その他参考書籍

オレンジの木

コード(TextWrangler)

sample.rb

#!/usr/bin/env ruby1.9
# -*- coding: utf-8 -*-

class OrangeTree
  def initialize
    @height = 0 
    @age = 0
    @alive = true
    @orange_count = 0
  end
  def height
    @height  
  end
  def age
    @age
  end
  def one_year_passes
    @orange_count = 0
    @age += 1 if @alive
    if (@age.class == Fixnum) && @age > 10
      @height = nil
      @age = nil
      @alive = false
    end
    @height += 5 if @alive
    @orange_count = @age * 2 if @alive && @age >= 5
  end
  
  def count_the_orange
    @orange_count
  end
  def pick_an_orange
    if ! @alive
      puts "もうオレンジの木は枯れているので実はとれません。"
    elsif @orange_count > 0
      puts "とても美味しいオレンジが採れました!"
      @orange_count -= 1
    elsif @age < 5
      puts "もう少し成長してからではないと実は採れません。"
    else
      puts "今年はもう採れる実がありません。"
    end
  end
end

ot = OrangeTree.new
puts "樹齢:#{ot.age} 高さ:#{ot.height} 実の数:#{ot.count_the_orange}"

11.times do
  ot.one_year_passes
  puts "樹齢:#{ot.age} 高さ:#{ot.height} 実の数:#{ot.count_the_orange}"
  (ot.count_the_orange + 1).times do
    ot.pick_an_orange
  end
end

入出力結果(Terminal)

$ ./sample.rb
樹齢:0 高さ:0 実の数:0
樹齢:1 高さ:5 実の数:0
もう少し成長してからではないと実は採れません。
樹齢:2 高さ:10 実の数:0
もう少し成長してからではないと実は採れません。
樹齢:3 高さ:15 実の数:0
もう少し成長してからではないと実は採れません。
樹齢:4 高さ:20 実の数:0
もう少し成長してからではないと実は採れません。
樹齢:5 高さ:25 実の数:10
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
今年はもう採れる実がありません。
樹齢:6 高さ:30 実の数:12
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
今年はもう採れる実がありません。
樹齢:7 高さ:35 実の数:14
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
今年はもう採れる実がありません。
樹齢:8 高さ:40 実の数:16
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
今年はもう採れる実がありません。
樹齢:9 高さ:45 実の数:18
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
今年はもう採れる実がありません。
樹齢:10 高さ:50 実の数:20
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
とても美味しいオレンジが採れました!
今年はもう採れる実がありません。
樹齢: 高さ: 実の数:0
もうオレンジの木は枯れているので実はとれません。
$

ちなみにJavaScriptの場合。

コード(TextWrangler)

<script>
var OrangeTree = function(){
  var height = 0;
  var age = 0;
  var alive = true;
  var orange_count = 0;
  this.height = function(){
    return height;
  };
  this.age = function(){
    return age;
  };
  this.one_year_passes = function(){
    orange_count = 0;
    if(alive) age += 1;
    if(age > 10){
       height = null;
       age = null
       alive = false; 
    }
    if(alive){
      height += 5;
      if(age >= 5){
        orange_count = age * 2;
      }
    }
  };
  this.count_the_orange = function(){
    return orange_count;
  };
  this.pick_an_orange = function(){
    if(!alive){
      return "もうオレンジの木は枯れているので実は採れません";
    } else if (orange_count > 0){
      orange_count -= 1;
      return "とても美味しいオレンジが採れました!";
    } else if(age < 5){
      return "もうすこし成長してからではないと実は採れません";
    } else {
      return "今年はもう採れる実がありません。";
    }
  };
};
var ot = new OrangeTree();
function age(){
  $('#d0').append("樹齢: " + ot.age() + "<br />");
}
function h(){
  $('#d0').append("高さ: " + ot.height() + "<br />");
}
function pick_an_orange(){
  $('#d0').append(ot.pick_an_orange() + "<br />");
}
function count_the_orange(){
  $('#d0').append("木になっている実の数: " + ot.count_the_orange() + "<br />");
}
</script>
<div id="d0">

</div>
<input type="button" value="樹齢" onclick="age()" />
<input type="button" value="高さ" onclick="h()" />
<input type="button" value="オレンジの実を1個収穫" onclick="pick_an_orange()" />
<input type="button" value="木になっている実の数" onclick="count_the_orange()" />
<input type="button" value="一年経過させる" onclick="ot.one_year_passes()" />
<input type="button" value="新しいオレンジの木を植える" onclick="ot = new OrangeTree()" />

pythonの場合。

sample.py

コード(TextWrangler)

#!/usr/bin/env python
# -*- coding: utf-8 -*-

class OrangeTree:
    def __init__(self):
        self.height = 0
        self.age = 0
        self.alive = True
        self.orange_count = 0
    
    def one_year_passes(self):
        self.orange_count = 0
        if self.alive: self.age += 1
        if (type(self.age) == type(10)) and self.age > 10:
            self.height = None
            self.age = None
            self.alive = False
        if self.alive:
            self.height += 5
            if self.age >= 5:
                self.orange_count = self.age * 2
    
    def pick_an_orange(self):
        if not self.alive:
            print("もうオレンジの木は枯れているので実は採れません。")
        elif self.orange_count > 0:
            print("とてもおいしいオレンジが採れました!")
            self.orange_count -= 1
        elif self.age < 5:
            print("もう少し成長してからではないと実は採れません。")
        else:
            print("今年はもう採れる実がありません。")

ot = OrangeTree()
print("樹齢:{0} 高さ:{1} 実の数:{2}".format(ot.age, ot.height, ot.orange_count))

for x in range(11):
    ot.one_year_passes()
    print("樹齢:{0} 高さ:{1} 実の数:{2}".format(ot.age, ot.height,
      ot.orange_count))
    for i in range(ot.orange_count + 1):
        ot.pick_an_orange()

入出力結果(Terminal)

kamimura$ ./sample.py
樹齢:0 高さ:0 実の数:0
樹齢:1 高さ:5 実の数:0
もう少し成長してからではないと実は採れません。
樹齢:2 高さ:10 実の数:0
もう少し成長してからではないと実は採れません。
樹齢:3 高さ:15 実の数:0
もう少し成長してからではないと実は採れません。
樹齢:4 高さ:20 実の数:0
もう少し成長してからではないと実は採れません。
樹齢:5 高さ:25 実の数:10
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
今年はもう採れる実がありません。
樹齢:6 高さ:30 実の数:12
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
今年はもう採れる実がありません。
樹齢:7 高さ:35 実の数:14
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
今年はもう採れる実がありません。
樹齢:8 高さ:40 実の数:16
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
今年はもう採れる実がありません。
樹齢:9 高さ:45 実の数:18
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
今年はもう採れる実がありません。
樹齢:10 高さ:50 実の数:20
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
とてもおいしいオレンジが採れました!
今年はもう採れる実がありません。
樹齢:None 高さ:None 実の数:0
もうオレンジの木は枯れているので実は採れません。
$

Pythonはデータの隠蔽が出来ない。上記のrubyやjavascriptのように、同じ名前のデータ属性とメソッドを定義する と上書きされる。データ属性の先頭に下線「_」を付け加えて読みやすくするようにしたり、メソッド名は動詞にするなどして回避はできるけど、外からアクセス、変更可能 である事には変わりはない。(pythonはデータの隠蔽、カプセル化はできない。)

データ属性とメソッドに分けた場合のクラス設計。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

class OrangeTree:
    def __init__(self):
        self._height = 0 # 変数名の先頭に下線を付ける
        self._age = 0
        self.alive = True
        self.orange_count = 0
    
    def height(self):
        return self._height
    
    def age(self):
        return self._age
    
    # メソッド名を動詞にする
    def count_the_orange:
        return self.orange_count

    def one_year_passes(self):
        self.orange_count = 0
        if self.alive: self._age += 1
        if (type(self._age) == type(10)) and self._age > 10:
            self._height = None
            self._age = None
            self.alive = False
        if self.alive:
            self._height += 5
            if self._age >= 5:
                self.orange_count = self._age * 2
    
    def pick_an_orange(self):
        if not self.alive:
            print("もうオレンジの木は枯れているので実は採れません。")
        elif self.orange_count > 0:
            print("とてもおいしいオレンジが採れました!")
            self.orange_count -= 1
        elif self._age < 5:
            print("もう少し成長してからではないと実は採れません。")
        else:
            print("今年はもう採れる実がありません。")

0 コメント:

コメントを投稿