Tbpgr Blog

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

Ruby | Factory Pattern 〜 CodeIQの参加者を生成する

概要

Factory Pattern 〜 CodeIQの参加者を生成する

詳細

Factory Patternは、インスタンス生成をサブクラスに任せるパターン。
Creatorにインスタンス生成の手順を受け持ち、
Creatorを継承したサブクラスがインスタンスの生成を受け持つ。

実装内容はTemplate Methodパターンと同じ。

サンプル1 仕様

CodeIQへの参加を実装します。
出題者、解答者が参加します。
出題者、解答者はそれぞれ名前を持ちます。

Factoryパターン上の役割は以下になります

ParticipationFactory => Creator
ProblemMasterFactory => ConcreteCreator
SolverFactory => ConcreteCreator
Participation(具体的に定義はせずparticipateメソッドでダックタイピング) => Product
ProblemMaster => ConcreteProduct
Solver => ConcreteProduct

サンプル1 コード

class ParticipationFactory
  def initialize(persons)
    @persons = []
    persons.each do |name|
      @persons << new_person(name)
    end
  end

  def participate
    @persons.each { |person|puts person.participate }
  end
end

class ProblemMaster
  def initialize(name)
    @name = name
  end

  def participate
    "#{@name}はCodeIQに出題者として参加してます"
  end
end

class ProblemMasterFactory < ParticipationFactory
  def new_person(name)
    ProblemMaster.new(name)
  end
end

class Solver
  def initialize(name)
    @name = name
  end

  def participate
    "#{@name}はCodeIQに解答者として参加してます"
  end
end

class SolverFactory < ParticipationFactory
  def new_person(name)
    Solver.new(name)
  end
end

pmf = ProblemMasterFactory.new(['tanaka', 'sato'])
pmf.participate

pmf = SolverFactory.new(['suzuki', 'honda'])
pmf.participate

出力

tanakaはCodeIQに出題者として参加してます
satoはCodeIQに出題者として参加してます
suzukiはCodeIQに解答者として参加してます
hondaはCodeIQに解答者として参加してます

サンプル2 仕様

基本仕様はサンプル1と同じ。
サンプル1は各クラスごとにFactoryクラスを作成するのですが、
ProductとFactoryを常にセットで作成する必要があり、もう少し効率化したいです。

そこで、CreatorであるParticipationFactoryに生成対象のクラスも一緒に渡すことにします。
これによってConcreteFactoryは不要になりました。

サンプル2 コード

require 'tbpgr_utils'

class ParticipationFactory
  def initialize(persons, classes)
    @persons = []
    [persons, classes].together { |name, klass|@persons << klass.new(name) }
  end

  def participate
    @persons.each { |person|puts person.participate }
  end
end

class ProblemMaster
  def initialize(name)
    @name = name
  end

  def participate
    "#{@name}はCodeIQに出題者として参加してます"
  end
end

class Solver
  def initialize(name)
    @name = name
  end

  def participate
    "#{@name}はCodeIQに解答者として参加してます"
  end
end

pmf = ParticipationFactory.new(
    ['tanaka', 'sato', 'suzuki', 'honda'], 
    [ProblemMaster, ProblemMaster, Solver, Solver]
  )
pmf.participate

__END__
togetherはtbpgr_utils gemの機能です。
複数のリストを同時にイテレートします。

詳しくは下記参照。
https://github.com/tbpgr/tbpgr_utils

出力

tanakaはCodeIQに出題者として参加してます
satoはCodeIQに出題者として参加してます
suzukiはCodeIQに解答者として参加してます
hondaはCodeIQに解答者として参加してます