vieweditattachhistoryswikistopchangessearchhelp

Ruby でお手軽にプロトタイプベース的 BankAccount

Io の スクリプト例の BankAccount の欄
Ruby でもクラス変数とクラスメソッドを使ってプロトタイプベース・オブジェクト指向スクリプティングを試してみています。っても、Smalltalk のプロトタイプベース的スクリプティングの単なる移植ですが。
を受けて。タイトルのものを試してみました。--sumim

--sumim

Smalltalk では、クラスのクラスはメタクラスと呼ばれ、クラスをオブジェクトとして振る舞わせるためのメソッド(クラスメソッド)はメタクラスに定義します(インスタンスにメッセージを送信することで起動するメソッドをクラスに定義するのと同じ考え方です)。それに対して、Ruby では、クラスメソッドは特異メソッドと呼ばれるオブジェクト(インスタンス)特異的なメソッドとして定義します。特異メソッドは、def オブジェクト.メッセージパターン ... end で定義することができるので、Ruby において“お手軽”に“プロトタイプベースっぽく BankAccount ”を実現するのには次のようすればよいことになります。
BankAccount=Class.new
def BankAccount.dollars; @dollars end
def BankAccount.dollars=(x); @dollars=x end
def BankAccount.deposit(x); self.dollars+=x end
def BankAccount.withdraw(x); self.dollars=[0,self.dollars-x].max end
BankAccount.dollars=200

BankAccount.dollars
=> 200
BankAccount.deposit(50)
=> 250
BankAccount.withdraw(100)
=> 150
BankAccount.withdraw(200)
=> 0

MyAccount=BankAccount.dup              # Ruby 1.6
  # MyAccount=Class.new(BankAccount)   # Ruby 1.8
MyAccount.dollars=100
MyAccount.deposit(400)
=> 500
BankAccount.dollars
=> 0

StockAccount=Class.new(BankAccount)
def StockAccount.numShares; @numShares end
def StockAccount.numShares=(x); @numShares=x end
def StockAccount.pricePerShare; @pricePerShare end
def StockAccount.pricePerShare=(x); @pricePerShare=x end
def StockAccount.dollars; self.numShares*self.pricePerShare end
def StockAccount.dollars=(x); self.numShares=Float(x)/pricePerShare; self.dollars end
StockAccount.numShares=10
StockAccount.pricePerShare=30

StockAccount.dollars
=> 300
StockAccount.dollars=150
=> 150.0
StockAccount.numShares
=> 5.0

MyStock=StockAccount.dup               # Ruby 1.6
   # MyStock=Class.new(StockAccount)   # Ruby 1.8
   # MyStock.numShares=10
   # MyStock.pricePerShare=30
MyStock.dollars=600
=> 600

MyStock.numShares
=> 20.0
MyStock.deposit(60)
=> 660.0
MyStock.numShares
=> 22.0
MyStock.withdraw(120)
=> 540.0
MyStock.numShares
=> 18.0

def BankAccount.deposit(x); self.dollars+=x*0.9 end

BankAccount.deposit(100)
==> 90.0    # 0 + 100 * 0.9
MyAccount.deposit(100)
==> 590.0   # 500 + 100 * 0.9
StockAccount.deposit(100)
==> 240.0   # 150 + 100 * 0.9
MyStock.deposit(100)
==> 630.0   # 540 + 100 * 0.9
--sumim



初めまして。snipと申します。
class << MyAccount; self end
とすると "#<Class:MyAccount>" という変なものが返ってくるのにこの間気づきました。
同様にいじってみると
>> class << Object.new; self end
=> #<Class:#<Object:0x298cc68>>
>> class A; end
=> nil
>> class << A.new; self end
=> #<Class:#<A:0x297e760>>
>> class << 1; self end
TypeError: no virtual class for Fixnum
        from (irb):10
        from :0
こういう不思議な反応がかえってきます。Smalltalkは詳しくないのですが、これはメタクラスにあたるものなのではないかと思います。表に出ないように設計されているようですね。 -- snip


これは特異クラスと呼ばれるインスタンス特異的な無名クラスです。ご推察の通り、Ruby の言語設計においてクラスの特異クラスは Smalltalk のメタクラスにあたります。ただ、クラス-インスタンス関係や、継承関係が Smalltalk より混沌としていて、個人的にはいまひとつ方針が理解できていません…(^_^;)。--sumim

関連:[はてな]「 Ruby の特異クラスの“振る舞い”のナゾ」


以前の、お手軽感に関するやりとり

このページを編集 (3905 bytes)


Congratulations! 以下の 5 ページから参照されています。

This page has been visited 5896 times.