メールの詳細(トピック表示)
Iterator patterns in Ruby
投稿者:TAKAHASHI Masayoshiさん 2001/09/17 20:11 MLNo.997 [メール表示]
高橋征義です。長文失礼します(_o_)
Rubyについて、話だけでは何なので、結城さんの『パターン入門本』の
サンプルをRubyで書いてみました。
『入門本』の最初のパターン、イテレータパターンのサンプルをそのまま
Rubyで書くと、以下のようになります。
# 行数を減らすために「;」を多用しています。ちょっと見辛いかも。
###--------------------------------------------- iterator_sample.rb
class Book
def initialize(name); @… = name; end
attr_reader :name
end
class BookShelf
def initialize(); @… = Array.new(); end
def book_at(index); return @…[index]; end
def append_book(book); @… << book; end
def length(); return @…; end
def iterator(); return BookShelfIterator.new(self); end
end
class BookShelfIterator
def initialize(bookshelf)
@… = bookshelf
@… = 0
end
def has_next?()
@… < @…()
end
def next()
book = @…_at(@…)
@… += 1
return book
end
end
### main
if __FILE__ == $0
bookShelf = BookShelf.new()
bookShelf.append_book(Book.new("Around the World in 80 Days"))
bookShelf.append_book(Book.new("Bible"))
bookShelf.append_book(Book.new("Cinderella"))
bookShelf.append_book(Book.new("Daddy-Long-Legs"))
it = bookShelf.iterator()
while it.has_next?
book = it.next()
print book.name, "\n"
end
end
#---------------------------------------------------------------------
もっとも、これは全然Rubyっぽくありません。そこで、
* メソッドをRubyっぽい名前/形にする
* イテレータをRuby標準の(インターナル)イテレータにする
* returnを省略する(最後に評価した値が返り値になります)
などの変更を行うと、以下のようになります。
###--------------------------------------------- iterator_sample3.rb
class Book
def initialize(name); @… = name; end
attr_reader :name
end
class BookShelf
def initialize(); @… = Array.new(); end
def [](index); @…[index]; end
def <<(book); @… << book; end
def length(); @…; end
def each(); @…{|book| yield(book)}; end
end
### main
if __FILE__ == $0
bookShelf = BookShelf.new()
bookShelf << Book.new("Around the World in 80 Days")
bookShelf << Book.new("Bible")
bookShelf << Book.new("Cinderella")
bookShelf << Book.new("Daddy-Long-Legs")
bookShelf.each{|book|
print book.name, "\n"
}
end
###------------------------------------------------------------------
さらに、「余計なメソッドが多少あってもいーじゃん」という気分の時は、
BookShelfはArrayのサブクラスにしてしまったりします。そうすると、
以下のようになります。クラス定義部分は10行足らずです。
# いやまあ、Arrayの機能をそのまま使ってるからなんですが(^^;;
###--------------------------------------------- iterator_sample4.rb
class Book
def initialize(name)
@… = name
end
attr_reader :name
end
class BookShelf < Array; end
### main
if __FILE__ == $0
#### (ここは iterator_sample3.rb と同じなので略)
end
#--------------------------------------------------------------------
……とまあ、Rubyでのプログラミングはこんな感じなのでした。
多少なりとも雰囲気が伝われば幸いです。
高橋征義 (TAKAHASHI Masayoshi) Email:maki@…
読み込み中...-
MLNo.998
結城浩さん
(0) 2001/09/17 20:52 [メール表示する]

高橋さん、結城です。
> Rubyについて、話だけでは何なので、結城さんの『パターン入門本』の
> サンプルをRubyで書いてみました。
ありがとうございます。面白いですねえ、これ。
結城は、具体的なコードが登場する話って大好きです。
この投稿(のバックナンバー)を以下からリンクしました。
http://www.hyuki.com/dp/index.html#link
ところで、
if __FILE__ == $0
というのはどういうイディオムになりますか?
----
結城浩
http://www.hyuki.com/
http://www.textfile.org/
Pray without ceasing. (Bible, I Thessalonians 5:17)

-
MLNo.1001
さん
(0) 2001/09/17 22:44 [メール表示する]

澤田です。
On Mon, 17 Sep 2001 20:12:59 +0900
in [DP/ML:0997] Iterator patterns in Ruby
TAKAHASHI Masayoshiwrote:
> 高橋征義です。長文失礼します(_o_)
> さらに、「余計なメソッドが多少あってもいーじゃん」という気分の時は、
> BookShelfはArrayのサブクラスにしてしまったりします。そうすると、
> 以下のようになります。クラス定義部分は10行足らずです。
> # いやまあ、Arrayの機能をそのまま使ってるからなんですが(^^;;
私は、Javaで書く場合にはコンテナ(コレクション)を継承して・・
なんてのは良くないだろう、と思っているのですが、Ruby だったら
許せてしまいますね。これもメソッドをメインで考えるからだと
思いました。
# そういえば Ruby にはモジュールなんてのもありますね。
___
澤田 大輔(die)
email: die@…(home), swd@…(office)

-
MLNo.1002
Tatsuhiko Miyagawaさん
(0) 2001/09/18 03:46 [メール表示する]

宮川です。
Perl だと配列にはイテレータは登場せず、ハッシュの each() がそれに
あたります。
オブジェクトをハッシュデータ構造と透過に扱う際に、tie ハッシュのイ
ンターフェースで NEXTKEY() というメソッドを実装しますが、これがま
さに iterator なので、それを内部的に使った実装のサンプルをつくって
みました。
というか、自分で実装は何もしてないんですけど ;)
use strict;
package Book;
use fields qw(name);
sub new {
my($class, $name) = @_;
my Book $self = fields::new($class);
$self->{name} = $name;
$self;
}
package Bookshelf;
use base qw(Tie::IxHash);
sub append_book {
my($self, $book) = @_;
$self->STORE($book => 1);
}
*next = \&Tie::IxHash::NEXTKEY;
package main;
my $shelf = Bookshelf->new;
$shelf->append_book(Book->new('Around the World in 80 Days'));
$shelf->append_book(Book->new('Bible'));
$shelf->append_book(Book->new('Cinderella'));
while (my Book $book = $shelf->next) {
print $book->{name}, "\n";
}
通常のハッシュでは key の順番が保存されないため、CPAN モジュールの
Tie::IxHash を使っています。
On Mon, 17 Sep 2001 20:12:59 +0900
TAKAHASHI Masayoshiwrote:
> Rubyについて、話だけでは何なので、結城さんの『パターン入門本』の
> サンプルをRubyで書いてみました。
--
Tatsuhiko Miyagawa mod_perl Mailing List
mailto:miyagawa@… http://bulknews.net/lib/ml/

-
MLNo.1003
結城浩さん
(0) 2001/09/18 05:26 [メール表示する]

宮川さん、結城です。
> Perl だと配列にはイテレータは登場せず、ハッシュの each() がそれに
> あたります。
そうですね。確かに、確かに。
いろんな言語で書くと、言語の違いがはっきりするとともに、
パターンの本質
(どういうプログラムを書いたら、そのパターンの例になっているか)
が少し浮かび上がってきますね。
> package main;
> my $shelf = Bookshelf->new;
> $shelf->append_book(Book->new('Around the World in 80 Days'));
> $shelf->append_book(Book->new('Bible'));
> $shelf->append_book(Book->new('Cinderella'));
>
> while (my Book $book = $shelf->next) {
> print $book->{name}, "\n";
> }
確かに、この部分(利用側)では、
Tie::IxHashの存在は隠されていますね。
宮川さんのメールを、
http://www.hyuki.com/dp/index.html#link
からリンクしました。
ちなみに、
『Java言語で学ぶデザインパターン入門』のJavaサンプルソースは、
http://www.hyuki.com/dp/index.html#download
にありますので、もし他言語に各パターンのサンプルを移植なさる方は
自由にご利用ください。
このMLに投稿(メールで、もしくはWebページのURLで)してくだされば、
http://www.hyuki.com/dp/index.html#link
などからリンクさせていただきます。
# [DP/ML]もメールの数が1000を越えました。
# みなさんのご参加を心から感謝します。
----
結城浩
http://www.hyuki.com/
http://www.textfile.org/
Pray without ceasing. (Bible, I Thessalonians 5:17)

-
MLNo.1010
SHIMADA Keikiさん
(0) 2001/09/19 23:40 [メール表示する]

こんにちは、Cakeと申します。
イテレータパターンを、現在入門中のSmalltalkで書いてみました。Ruby と同じ
ように、内部イテレータを使っています。メソッド名なども Smalltalk の慣習
に合わせました。
Smalltalkのソースコードはシーケンシャルなテキストファイルではないのです
が、クラス定義、インスタンスメソッド定義、メタクラス定義、クラスメソッド
定義の順番で並べてみました。メソッド定義の前には
"クラス>カテゴリ>メッセージセレクタ"
というコメントをつけています。
(Smalltalkでは二重引用符 "..." がコメントになります。)
# なにぶん入門中の身の上なので、おかしなことを書いているかもしれません。
# お気づきの点はご指摘頂ければ幸いです。
"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "
Object subclass: #Book
instanceVariableNames: 'name '
classVariableNames: ''
poolDictionaries: ''
category: 'Patterns-Example'
"Book>initialize-release>initialize:"
initialize: aString
name := aString
"Book>accessing>name"
name
^ name
"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "
Book class
instanceVariableNames: ''
"Book class>instance creation>new:"
new: aString
^ self new initialize: aString
"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "
Object subclass: #BookShelf
instanceVariableNames: 'books '
classVariableNames: ''
poolDictionaries: ''
category: 'Patterns-Example'
"BookShelf>initialize-release>initialize:"
initialize: anInteger
books := OrderedCollection new: anInteger
"BookShelf>accessing>add:"
add: aBook
books add: aBook
"BookShelf>accessing>at:"
at: anInteger
^ books at: anInteger
"BookShelf>accessing>size"
size
^ books size
"BookShelf>enumerating>do:"
do: aBlock
books do: [:each | aBlock value: each]
"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "
BookShelf class
instanceVariableNames: ''
"BookShelf class>instance creation>new:"
new: anInteger
^ self new initialize: anInteger
"BookShelf class>examples>examples"
example
"BookShelf example."
| aBookShelf |
aBookShelf := BookShelf new: 4.
aBookShelf add: (Book new: 'Around the World in 80 Days').
aBookShelf add: (Book new: 'Bible').
aBookShelf add: (Book new: 'Cinderella').
aBookShelf add: (Book new: 'Daddy-Long-Legs').
aBookShelf do: [:each | Transcript show: each name; cr].
^ aBookShelf
--
SHIMADA, Keiki (島田慶樹)
cake-smd@…
http://www.ops.dti.ne.jp/~cake-smd/
Smalltalk allBehaviorsDo:[:each | each praise: 'Halleluja!!']

-
MLNo.1011
Masashi Umezawaさん
(0) 2001/09/20 14:12 [メール表示する]

こんにちは
梅澤です。
On Tue, 18 Sep 2001 21:23:12 +0900
SHIMADA Keikiwrote:
> イテレータパターンを、現在入門中のSmalltalkで書いてみました。Ruby と同じ
> ように、内部イテレータを使っています。メソッド名なども Smalltalk の慣習
> に合わせました。
いくつか細かい点はあるのですが、内部イテレータをBookShelfが実装する
必要があるのか、という点がもっとも気になりました。
BookShelfに、
"BookShelf>accessing"
books
^books
というアクセッサさえ用意しておけば、イテレートは、
bookshelf books do: [:each | なんたら...].
で事足りるのではないでしょうか。
BookShelfに内部イテレータを作るのは、イテレートの仕方がよほど
特殊な場合に限られると思います。
あとは、細かな点。
new: は通常、コレクション系クラスで使われ、サイズが引数となるのが
普通です。BookShelfの場合はまだしも、Bookのnew:は、named: などと
したほうが良いでしょう。
また、initializeで引数ありというのも、この規模のクラスに適用する
べきではないと思います。
DP+Smalltalkという話題ですと、
"Design Patterns Smalltalk Companion" という洋書があります。
GoFのDPをSmalltalkの観点から考察しなおしたものです。
http://cseng.aw.com/book/0,3828,0201184621,00.html
Rubyもそうかと思うのですが、動的言語では、パターンの実装が楽になったり、
パターンそのものが不要になる場合などがあります。
興味がありましたらどうぞ。
---
[:masashi | ^umezawa]

-
MLNo.1013
OZAWA -Crouton- Sakuroさん
(0) 2001/09/20 15:00 [メール表示する]

さくです。
At Mon, 17 Sep 2001 20:12:59 +0900,
TAKAHASHI Masayoshi wrote:
> さらに、「余計なメソッドが多少あってもいーじゃん」という気分の時は、
> BookShelfはArrayのサブクラスにしてしまったりします。そうすると、
> 以下のようになります。クラス定義部分は10行足らずです。
> # いやまあ、Arrayの機能をそのまま使ってるからなんですが(^^;;
継承を使うと、 Array と BookShelf が is-a の関係になっちゃうんですよね。
「継承は最後の武器」という言葉もありますから、 delegator を使うのも Ruby
っぽいかも。
require 'delegate'
class BookShelf < DelegateClass(Array)
def initialize(); super([]); end
end
あとは同じですね。
DelegateClass は、 delegate.rb で定義されているメソッドで、以下のメソッド
群を持った名前のないクラスを作り、返します。
* 引数のクラスのインスタンスを引数にとり、インスタンス変数 @… に代入する
initialize メソッド
* @… がもつほぼ全て (*) のメソッドに対し、@… に委譲するだけの同名メソッド
返されたクラスを継承して BookShelf を定義し、その initialize メソッドでは
委譲先である Array クラスのインスタンス ([]) を作り、 super を使って、
(DelegateClass の返した) 名前のないクラスの initialize メソッドに渡してい
ます。
また、 delegate.rb では、委譲されるメソッドはほぼ全てになってしまいますが、
選択的に委譲する場合は、最近の Ruby に入っている forwardable.rb が使えます。
*: 「ほぼ」なのは、委譲する意味のないメソッドやすべきでないメソッドがある
からです。
--
OZAWA -Crouton- Sakuro
E-Mail: mailto:crouton@…
Web: http://www.weatherlight.org/~crouton/
PGP: C98F 74E0 AEEB 4578 1DFC F650 3BE0 9627 11FC C9F5
VERBA VOLANT, SCRIPTA MANENT

-
MLNo.1021
SHIMADA Keikiさん
(0) 2001/09/28 06:35 [メール表示する]

こんにちは、Cakeです。
At Thu, 20 Sep 2001 14:13:20 +0900,
Masashi Umezawa wrote:
>
> いくつか細かい点はあるのですが、内部イテレータをBookShelfが実装する
> 必要があるのか、という点がもっとも気になりました。
(略)
> BookShelfに内部イテレータを作るのは、イテレートの仕方がよほど
> 特殊な場合に限られると思います。
なるほど。
> new: は通常、コレクション系クラスで使われ、サイズが引数となるのが
> 普通です。BookShelfの場合はまだしも、Bookのnew:は、named: などと
> したほうが良いでしょう。
勘違いでした。
> また、initializeで引数ありというのも、この規模のクラスに適用する
> べきではないと思います。
単純でいいものは単純なままにしておく、ということでしょうか。
> DP+Smalltalkという話題ですと、
> "Design Patterns Smalltalk Companion" という洋書があります。
洋書は苦手ですが、機会があれば読んでみたいと思います。
* * * *
やはり実地に使ってらっしゃる方に見てもらうと、いろいろ勉強になりますね。
ありがとうございました。
--
Cake (SHIMADA Keiki)
mailto:cake-smd@…
http://www.ops.dti.ne.jp/~cake-smd/
Smalltalk allBehaviorsDo:[:each | each praise: 'Halleluja!!']


