Tbpgr Blog

Employee Experience Engineer tbpgr(てぃーびー) のブログ

書籍 リファクタリング−プログラマーの体質改善 | データの再編成 | 単方向関連の双方向への変更

内容

リファクタリング

単方向関連の双方向への変更

適用ケース要約

相互に参照が必要なクラスがあるが、片方からの参照しかない

適用内容要約

双方向に参照するように変更を行う。

適用詳細

A→Bへの参照が存在し、逆が存在しない場合。
B→Aへの参照を追加する。

サンプル

著者と読者の関係を実装します。
読者は自分が読んでいる本の著者に関心を持ちます。
はじめは一方的な関係であったため、単方向で実装しました。

昨今、Twitterなどで著者側が読者側に関心を持つこともあるため
双方向へリファクタリングします。

サンプルコード

リファクタリング

# encoding: Shift_JIS
require 'set'

class BookReader
  attr_reader:author
  attr_accessor:name
  
  def initialize(author,name)
    @author=author
    @name=name
  end
  
  def answer_author_name()
    puts "私(#{@name})が読んでいる本の著者は#{@author.name}です"
  end
end

class Author
  attr_accessor:name
  
  def friend_book_readers()
    @book_readers
  end
  
  def initialize(name)
    @name=name
    @book_readers=Set.new
  end
  
  def add_book_reader(book_reader)
    @book_readers.add book_readers
  end
end

yuki = Author.new("結城浩")
tanaka = BookReader.new(yuki,"田中")
suzuki = BookReader.new(yuki,"鈴木")
fowler = Author.new("マーティン・ファウラー")
sato = BookReader.new(fowler,"佐藤")

tanaka.answer_author_name
suzuki.answer_author_name
sato.answer_author_name

出力(リファクタリング前)

私(田中)が読んでいる本の著者は結城浩です
私(鈴木)が読んでいる本の著者は結城浩です
私(佐藤)が読んでいる本の著者はマーティン・ファウラーです

リファクタリング

# encoding: Shift_JIS
require 'set'

class BookReader
  attr_reader:author
  attr_accessor:name
  
  def initialize(author,name)
    @author=author
    set_author(author)
    @name=name
  end
  
  def answer_author_name()
    puts "私(#{@name})が読んでいる本の著者は#{@author.name}です"
  end
  
  def set_author(author)
     @author.friend_book_readers.delete(self) unless @author.nil?
     @author.friend_book_readers.add(self) unless @author.nil?
  end
end

class Author
  attr_accessor:name,:book_readers
  
  def friend_book_readers()
    @book_readers
  end
  
  def initialize(name)
    @name=name
    @book_readers=Set.new
  end
  
  def answer_book_readers
    message = ""
    book_readers.each {|reader|
      message << "#{reader.name}さん、"
    }
    message << "は私(#{@name})の本の読者です"
    puts message
  end
end

yuki = Author.new("結城浩")
tanaka = BookReader.new(yuki,"田中")
suzuki = BookReader.new(yuki,"鈴木")
fowler = Author.new("マーティン・ファウラー")
sato = BookReader.new(fowler,"佐藤")

tanaka.answer_author_name
suzuki.answer_author_name
sato.answer_author_name
yuki.answer_book_readers
fowler.answer_book_readers

出力(リファクタリング後)

私(田中)が読んでいる本の著者は結城浩です
私(鈴木)が読んでいる本の著者は結城浩です
私(佐藤)が読んでいる本の著者はマーティン・ファウラーです
田中さん、鈴木さん、は私(結城浩)の本の読者です
佐藤さん、は私(マーティン・ファウラー)の本の読者です