Movatterモバイル変換


[0]ホーム

URL:


酒と泪とRubyとRailsと

イーテレータ | Ruby デザインパターン


GoFのデザインパターンのイーテレータ(Iterator)のRubyコードを使った紹介記事です。イーテレーターパターンは次のような場合に使います。

  • 要素の集まったオブジェクト(配列など)にアクセスする
  • 集合の要素に順にアクセスする必要がある

😎イーテレータとは?

GoFではイーテレータを「集約オブジェクトがもとにある内部表現を公開せずに、その要素に順にアクセスする方法を提供する」と定義しています。

言い換えると、要素の集まりをもつオブジェクトの各要素に、順番にアクセスする方法を提供するためのデザインパターンです。

🚕内部イーテレータ

Rubyのeachと同じもの。コードブロックベースのイーテレータのこと。

🐯外部イーテレータ

ここでは次のようなモデルで外部イーテレータを説明します。

  • Blogクラス(集約オブジェクト): 複数のArticleクラスをもつオブジェクト
  • Articleクラス(集約オブジェクト内の要素):Blogクラスの個別の要素
  • BlogIteratorクラス(外部イーテレータ):Blogの要素Articleにアクセスするためクラス

まず、記事を表すArticleクラスです。

# 記事を表す(集約オブジェクト中の要素)
classArticle
definitialize(title)
@title = title
end

# 記事のタイトル
attr_reader:title
end

次は、記事を複数もつブログを表すBlogクラスです。

# ブログを表す(集約オブジェクト)
classBlog
definitialize
@articles = []
end

# 指定インデックスの要素を返す
defget_article_at(index)
@articles[index]
end

# 要素(Article)を追加する
defadd_article(article)
@articles<< article
end

# 要素(Article)の数を返す
deflength
@articles.length
end

# イーテレータの生成
defiterator
BlogIterator.new(self)
end
end

最後に外部イーテレータのBlogIteratorクラスです。

# 外部イーテレータ
classBlogIterator
definitialize(blog)
@blog = blog
@index =0
end

# 次のindexの要素が存在するかをtrue/falseで返す
defhas_next?
@index< @blog.length
end

# indexを1つ進めて、次のArticleクラスを返す
defnext_article
article =self.has_next? ? @blog.get_article_at(@index) :nil
@index = @index +1
article
end
end

ソースコードは以上です。では、実際の動作を確認してみます。

blog = Blog.new
blog.add_article(Article.new("デザインパターン1"))
blog.add_article(Article.new("デザインパターン2"))
blog.add_article(Article.new("デザインパターン3"))
blog.add_article(Article.new("デザインパターン4"))

iterator = blog.iterator
while iterator.has_next?
article = iterator.next_article
puts article.title
end
#デザインパターン1
#デザインパターン2
#デザインパターン3
#デザインパターン4

blog.iteratorで生成した外部イーテレータによって、Blogクラスの要素Articleに順番にアクセスできていることがわかります。

🍮Enumerableモジュール

唐突ですが、Rubyの便利モジュールEnumerableの紹介です。Enumerableモジュールをインクルードすると、集約オブジェクト向けの「all?any?include?」といった便利なメソッドを取り込むことができます。

以下は取り込んだ場合のサンプルソースです。

classAccount
attr_accessor:name,:balance

definitialize(name, balance)
@name = name
@balance = balance
end

def<=>(other)
@balance<=> other.balance
end
end

classPortfolio
include Enumerable

definitialize
@accounts = []
end

defeach(&block)
@accounts.each(&block)
end

defadd_account(account)
@accounts<< account
end
end

portfolio = Portfolio.new
portfolio.add_account(Account.new("account1",1000))
portfolio.add_account(Account.new("account2",2000))
portfolio.add_account(Account.new("account3",3000))
portfolio.add_account(Account.new("account4",4000))
portfolio.add_account(Account.new("account5",5000))

# $3000より多く所有している口座があるか?
puts portfolio.any? {|account| account.balance >3000 }
#=> true

# すべての口座が$2000以上あるか?
puts portfolio.all? {|account| account.balance >=2000 }
#=> false

😸サンプルソース

🤔参考リンク

🖥 VULTRおすすめ

VULTR」はVPSサーバのサービスです。日本にリージョンがあり、最安は512MBで2.5ドル/月($0.004/時間)で借りることができます。4GBメモリでも月20ドルです。 最近はVULTRのヘビーユーザーになので、「ここ」から会員登録してもらえるとサービス開発が捗ります!

📚 おすすめの書籍

Rails/Modelバリデーションコールバック変更前後の値の確認値の保存・更新アソシエーション削除メソッドSQLの実行日付カラムの設定便利なDB関連設定読込み専用(Read Only)Concern(共通処理)クエリTipsRails/Controllerrenderレシピ集HTTPステータスシンボルIPの取得についてStrong ParametersControllerのTipsRails/ViewHAMLチートシート画像アップロードフォームS3への画像アップロードForm Objectフォームヘルパー検索可能なselectタグenum - selectタグシンプルな検索ボックス別ウィンドウ・フォームRailsいろいろi18nについてRails.cacheメール送信ロギングCapistrano3でデプロイセッション管理環境ごとのYAML設定読込xx分前の時間表記Tipsいろいろ便利ライブラリ簡単Webmock:VCRN+1対策:bullet環境変数の管理: dotenvi18nサポート: i18n-tasksLDAP:net-ldapヘッダ:secureheadersrack-mini-profileractiverecord-precountカバレッジ計測パンくずリスト+MetadataRSpecの記法自動修正アプリランキング取得Unicorn導入手順unicorn-worker-killerRSpecController SpecCapybaraとヘッドレスChromeRequest SpecAPI認証 Spec便利Tipsデザインパターン概要アブストラクトファクトリビルダファクトリメソッドアダプタコンポジットデコレータプロキシコマンドインタプリタイテレータオブザーバストラテジテンプレートメソッドRuby基礎文字列/String配列/Arrayハッシュ/Hash構造体/StructSpawn(コマンド実行)BundlerについてTipsRails 5.1へのアップデートRails 5へのアップデートrbenvバージョンアップpumaをsystemdで動かすURI.encodeとCGI.escapeURLのパラメータを変更処理時間を計測画像JPEG/PNG/GIF判定トラブルシュートNo route matches assets

[8]ページ先頭

©2009-2025 Movatter.jp