NOEMBLEM/エンブレムが設定されていません。

メールの詳細(トピック表示)

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 Masayoshi wrote:

    > 高橋征義です。長文失礼します(_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 Masayoshi wrote:

    > 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 Keiki wrote:

    > イテレータパターンを、現在入門中の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!!']



メールへの返信はMLのメンバーしかできません。
【PR】ステキなブログ楽しい掲示板みんなの日記かんたんブログ女の子向けブログ
4LDK超ってこんなに広い?/SUUMO