LoginSignup
6
3

More than 3 years have passed since last update.

書籍Java言語で学ぶデザインパターン入門」をRubyで書いてみて分かったこと

Last updated at Posted at 2019-12-10

はじめに

この記事は Ruby Advent Calendar 2019 の11日目の記事です。

現在、エンジニアになって9ヶ月が経ったのですが、最近は、オブジェクト指向やデザインパターンのような基礎的な部分を理解しようと努めており、ここ1~2ヶ月で下記5冊の本を読みました。

これらの本を読むことで、オブジェクト指向というものの輪郭がぼんやりと掴めてきた気がするのと、改めてRubyという言語の特徴を知るキッカケになったと感じております。

本記事では、書籍「Java言語で学ぶデザインパターン入門」の1章(Iterator)のJavaで書かれたコードサンプルをRubyで書くとどうなるかを自分なりに咀嚼しながら実践してみたこと、および、学んだことについてアウトプットしていきます。

※ 以下で書くことは、個人的には「そういうことか!」と点と点が繋がる感覚を覚えた出来事だったのですが、Rubyをやっている方にとっては当たり前の話かもしれません。温かい目でご覧いただければ幸いです。

サンプルコード

GitHubはこちらです。
https://github.com/MasashiFukuzawa/DesignPatternLearnedWithRuby

今回のサンプルの概要

本棚に本を入れ、その本の名前を順番に表示するサンプルをRubyを使って、Iteratorパターンで記述していきます。

JavaサンプルをRubyで直訳してみる

まずはJavaのサンプルコードを直訳したものを示します。

この実装では、AggregateクラスとIteratorクラスという基底クラスを明示しています。

こうすることで、例えば、新たにCDラックににCDを入れ、そのCDの名前を順番に表示したくなった場合も、AggregateクラスとIteratorクラスを継承し、本棚とCDラックが同じインターフェースを共有していることが一目で理解できるようになります。

# interface
class Aggregate
  def iterator
  end
end

# interface
class Iterator
  def has_next?
  end

  def next
  end
end

# interfaceの実装
class Bookshelf < Aggregate
  def initialize(maxsize)
    @books = Array.new(maxsize)
    @last  = 0
  end

  def append_book(book)
    @books << book
    @last += 1
  end

  def getBookAt(index)
    @books[index]
  end

  def getLength
    @last
  end

  def iterator
    BookshelfIterator.new(self)
  end
end

# interfaceの実装
class BookshelfIterator < Iterator
  def initialize(bookshelf)
    @bookshelf = bookshelf
    @index = 0
  end

  def has_next?
    @index < @bookshelf.getLength
  end

  def next
    book = @bookshelf.getBookAt(@index)
    @index += 1
    book
  end
end

# 動作テスト
bookshelf = Bookshelf.new(4)
bookshelf.append_book('1st book')
bookshelf.append_book('2nd book')
bookshelf.append_book('3rd book')
bookshelf.append_book('4th book')

it = bookshelf.iterator

while it.has_next? do
  book = it.next
  puts book
end

# 実行結果
> 1st book
> 2nd book
> 3rd book
> 4th book

しかしながら、上記のコードでは、AggregateクラスとIteratorクラスは何もせず、ただインターフェースを規定するためだけに存在しているため、Ruby的な手法ではないようです。

そこで、次にRubyらしく書いたコードを見ていきます。

Rubyらしく書いてみる

修正点としては、上記のサンプルからインターフェースクラスおよび継承部分を削除しただけです。

この場合、基底クラスを明示していないため、先程挙げた例のように、新たにCDラック用の実装が追加された時などに、本棚でもCDラックでも同じような動きはするものの、それぞれが同じインターフェースを共有していることが分からなくなるのでは?とどうしても最初は心配になってしまいました。

しかしながら、ずっと考えているうちに、そのような心配をせずとも、いずれもiteratorメソッドを通して同じ挙動を示す(アヒルのように歩き、アヒルのように鳴く)ことで、同じインターフェースを共有していることを見抜けるってことか!ということがスッと腹落ちしたのでした。

そして、これこそが今までずっと上手く咀嚼できずにいた「ダックタイピング」という言葉の意味であり、Rubyという言語の特徴なのだと理解した瞬間に、個人的には「そういうことか!」と点と点が繋がったのでした。

class Bookshelf
  def initialize(maxsize)
    @books = Array.new(maxsize)
    @last  = 0
  end

  def append_book(book)
    @books << book
    @last += 1
  end

  def getBookAt(index)
    @books[index]
  end

  def getLength
    @last
  end

  def iterator
    BookshelfIterator.new(self)
  end
end

class BookshelfIterator
  def initialize(bookshelf)
    @bookshelf = bookshelf
    @index = 0
  end

  def has_next?
    @index < @bookshelf.getLength
  end

  def next
    book = @bookshelf.getBookAt(@index)
    @index += 1
    book
  end
end

# 動作テスト
bookshelf = Bookshelf.new(4)
bookshelf.append_book('1st book')
bookshelf.append_book('2nd book')
bookshelf.append_book('3rd book')
bookshelf.append_book('4th book')

it = bookshelf.iterator

while it.has_next? do
  book = it.next
  puts book
end

# 実行結果
> 1st book
> 2nd book
> 3rd book
> 4th book

オブジェクト指向・デザインパターンを勉強して理解したこと

  • Rubyの場合は、わざわざ何もしない基底クラスを作って押し込めるようなことはせずとも大丈夫
  • 例えば、Bookshelfクラスと同様の形でCDRackクラスも実装した場合、基底クラスが明示されていなくても、いずれもiteratorメソッドを通して同じ挙動を示す(アヒルのように歩き、アヒルのように鳴く)ことで、同じインターフェースを共有していることを見抜ける
  • そしてこれこそがよく耳にする「ダックタイピング」である

まとめ

  • Java言語で学ぶデザインパターン入門をRubyで書くとどうなるかについて試してみました。
  • ここ1~2ヶ月間、オブジェクト指向およびデザインパターンを重点的に勉強した結果、遅ればせながら、Rubyやダックタイピングへの理解が深まり、点と点が繋がる感覚を覚えることができました。
  • やっとオブジェクト指向の入口に立てたかなという感じなので、今後も引き続き、咀嚼&アウトプットしていきたいと思います。

参考書籍

6
3
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
3