パンくず
書籍 Patterns to Patterns
Creation
Encapsulate Classes with Factory
概要
Encapsulate Classes with Factoryのリファクタリングについて
使用する場面
一つのインターフェースを実装したクラスが複数あった場合に、
必要最低限のクラスのみ外部に公開したい。
対応方法
クラスの実装をFactoryで隠蔽する。
利点と欠点
手順
1.いろんな種類のインスタンスを直接生成しているクライアントを見つける。
コンストラクタにpublic staticな"Extract Method"を適用する。
この新たなメソッドはCreation Methodです。
スーパークラスに"Move Method"を適用する。
2.全てのコンストラクタ利用箇所を探し、Creation Methodを呼ぶように修正する。
3.他のインスタンスにも1~2を繰り返す
4.コンストラクタをnon-pulbicにする。
5.あなたの望むカプセル化になるまで全てのクラスに1~4を繰り返す
サンプル
プログラム言語クラス(ProgrammingLanguage)があり、これを継承したJavaクラス(Java)とRubyクラス(Ruby)があります。
これを参照するクライアントに対しては、JavaとRubyの実装は意識させないようにします。
リファクタリング前
# encoding: Windows-31J class ProgrammingLanguage attr_accessor:name def initialize(name);@name = name;end def coding();puts "コーディング";end end class Java < ProgrammingLanguage JAVA = "Java" def initialize;@name = JAVA;end def coding();puts "Javaでコーディング";end end class Ruby < ProgrammingLanguage RUBY = "Ruby" def initialize;@name = RUBY;end def coding();puts "Rubyでコーディング";end end class Client def use_language(language_name) language = nil if language_name == Java::JAVA language = Java.new elsif language_name == Ruby::RUBY language = Ruby.new end language.coding end end [Java::JAVA,Ruby::RUBY].each {|language_name|Client.new.use_language(language_name)}
リファクタリング後
Factoryメソッドを導入後、さらにDart言語を追加しました。
既存クラスへの影響なく追加出来ました。
# encoding: Windows-31J @JAVA = "Java" @RUBY = "Ruby" class ProgrammingLanguage attr_accessor:name def initialize(name);@name = name;end private:initialize def self.get_java_language() return Java.new(@JAVA) end def self.get_ruby_language() return Ruby.new(@RUBY) end def coding();puts "コーディング";end end class Java < ProgrammingLanguage def initialize(language);@name = @JAVA;end protected:initialize def coding();puts "Javaでコーディング";end end class Ruby < ProgrammingLanguage def initialize(language);@name = @RUBY;end protected:initialize def coding();puts "Rubyでコーディング";end end puts ProgrammingLanguage::get_java_language.coding puts ProgrammingLanguage::get_ruby_language.coding