概要
GoFのデザインパターンのFacadeパターンについて。
複雑な手順の処理の窓口=Facadeを用意することで
システムをシンプルにする。
登場人物
Facade = 窓口
ModuleA = 処理A
ModuleB = 処理B
Client = 利用者
実装サンプル
サンプル概要
親子構造を持つクラスを生成するジェネレーターを実装します。
ジェネレーターの利用者は親子クラスジェネレーターに親クラス名、子クラス名、
テストクラスの生成有無を渡すして、コード生成メソッドを呼ぶことで
ファイルの生成を行うことが出来ます。
親子クラスジェネレーターがFacadeにあたります。
利用者は親子クラスジェネレーターのコード生成メソッドのインターフェースのみを知っていれば問題ありません。
親子クラスジェネレーターのコード生成メソッドでは、引数で受けとったクラス名で
親クラスジェネレーターと子クラスジェネレーターを順に呼び出してクラスを生成します。
さらに、テストクラス生成有無が真ならテストクラスジェネレーターを呼び出して
テストクラスを作成します。
各クラスの責務は以下の登場人物に記述した内容になります。
登場人物
Facade = FamilyClassGenerator:継承構造を持つクラスを生成する窓口
ModuleA = ClassGenerator:クラス生成の基底クラス
ModuleB = ParentClassGenerator:親クラスを生成
ModuleC = ChildClassGenerator:子クラスを生成
ModuleD = TestClassGenerator:テストクラスを生成
Client = User:親子クラスジェネレーターの利用者
サンプルコード
FamilyClassGenerator
# encoding: Shift_JIS require_relative './parent_class_generator' require_relative './child_class_generator' require_relative './test_class_generator' =begin rdoc = FamilyClassGeneratorクラス =end class FamilyClassGenerator def generate_code(parent_name,child_names,has_test_class) parent_class_generator = ParentClassGenerator.new child_class_generator = ChildClassGenerator.new test_class_generator = TestClassGenerator.new parent_class_generator.generate_class(parent_name,nil,false) test_class_generator.generate_class("Test#{parent_name}",nil,false) if has_test_class child_names.each{|child| child_class_generator.generate_class(child,parent_name,true) test_class_generator.generate_class("Test#{child}",nil,false) if has_test_class } end end
class_generator
# encoding: Shift_JIS require_relative './string_util' =begin rdoc = ClassGeneratorクラス =end class ClassGenerator NOT_OVERRRIDE = 'not override error' def generate_class(class_name,parent_name,has_parent) if has_parent code = generate_code(class_name,parent_name) else code = generate_code(class_name) end output_class_file(class_name,code) end private def output_class_file(class_name,code) snake_file_name = StringUtil.to_snake_case class_name file_path = "./output/#{snake_file_name}.rb" folder_path=File::dirname file_path Dir::mkdir folder_path unless FileTest.exist?(folder_path) File::delete(file_path) if FileTest.exist?(file_path) file = open(file_path,"w") file.puts code file.close end protected def generate_code(class_name,parent_name) raise NOT_OVERRRIDE end protected def generate_code(class_name) raise NOT_OVERRRIDE end end
parent_class_generator
# encoding: Shift_JIS require_relative './class_generator' =begin rdoc = ParentClassGeneratorクラス =end class ParentClassGenerator < ClassGenerator def generate_code(class_name) code =<<"EOS" class #{class_name} end EOS return code end end
child_class_generator
# encoding: Shift_JIS require_relative './class_generator' =begin rdoc = ChildClassGeneratorクラス =end class ChildClassGenerator < ClassGenerator def generate_code(class_name,parent_name) snake_file_name = StringUtil.to_snake_case parent_name code =<<"EOS" require_relative './#{snake_file_name}' class #{class_name} < #{parent_name} end EOS return code end end
test_class_generator
# encoding: Shift_JIS require_relative './class_generator' =begin rdoc = TestClassGeneratorクラス =end class TestClassGenerator < ClassGenerator def generate_code(class_name) snake_file_name = StringUtil.to_snake_case(class_name.sub('Test','')) code =<<"EOS" require 'test/unit' require_relative './#{snake_file_name}' class #{class_name} < Test::Unit::TestCase end EOS return code end end
user
# encoding: Shift_JIS require_relative './family_class_generator' =begin rdoc = Userクラス =end class User def call_generate_family_class(parent_name,child_names,has_test_class) class_generator = FamilyClassGenerator.new class_generator.generate_code(parent_name,child_names,has_test_class) end end
string_util
# encoding: Shift_JIS class StringUtil def self.to_snake_case(str) ret = str.gsub(/([A-Z].)/,'_\1').downcase ret = ret.slice(1,ret.size) return ret end # パスからファイル名を除外した文字列を取得 def self.get_folder_path(file_path) folders = file_path.split('/') folders.pop folder_path = "" folders.each {|folder| folder_path << folder folder_path << "/" } return folder_path end # ファイル名のみを取得 def self.get_file_name(file_path) folders = file_path.split('/') return folders[folders.size-1] end # 拡張子なしファイル名の取得 def self.get_file_name_without_extension(file_name) file_names = file_name.split('.') return file_names[0] end end
main
# encoding: Shift_JIS require_relative './user' user = User.new child_classes = ["ChildFirst","ChildSecond","ChildThird"] user.call_generate_family_class("Parent",child_classes,true) other_child_classes = ["OtherChildFirst","OtherChildSecond","OtherChildThird"] user.call_generate_family_class("OtherParent",other_child_classes,false) puts `ls -ltr ./output | sort` puts "--------------------------------" puts `cat ./output/parent.rb` puts "--------------------------------" puts `cat ./output/test_parent.rb` puts "--------------------------------" puts `cat ./output/child_first.rb` puts "--------------------------------" puts `cat ./output/test_child_first.rb`
出力
-rwxr-xr-x+ 1 ***** Domain Users 21 Feb 27 21:36 parent.rb -rwxr-xr-x+ 1 ***** Domain Users 26 Feb 27 21:36 other_parent.rb -rwxr-xr-x+ 1 ***** Domain Users 63 Feb 27 21:36 child_first.rb -rwxr-xr-x+ 1 ***** Domain Users 63 Feb 27 21:36 child_third.rb -rwxr-xr-x+ 1 ***** Domain Users 64 Feb 27 21:36 child_second.rb -rwxr-xr-x+ 1 ***** Domain Users 79 Feb 27 21:36 other_child_first.rb -rwxr-xr-x+ 1 ***** Domain Users 79 Feb 27 21:36 other_child_third.rb -rwxr-xr-x+ 1 ***** Domain Users 80 Feb 27 21:36 other_child_second.rb -rwxr-xr-x+ 1 ***** Domain Users 98 Feb 27 21:36 test_parent.rb -rwxr-xr-x+ 1 ***** Domain Users 107 Feb 27 21:36 test_child_first.rb -rwxr-xr-x+ 1 ***** Domain Users 107 Feb 27 21:36 test_child_third.rb -rwxr-xr-x+ 1 ***** Domain Users 109 Feb 27 21:36 test_child_second.rb total 12 -------------------------------- class Parent end -------------------------------- require 'test/unit' require_relative './parent' class TestParent < Test::Unit::TestCase end -------------------------------- require_relative './parent' class ChildFirst < Parent end -------------------------------- require 'test/unit' require_relative './child_first' class TestChildFirst < Test::Unit::TestCase end