Contents
- 1. Factory Method
- 1.1. Intent : μλ
- 1.2. Also Known As : λΉμ·ν, νΉμ λμΌν μν μ νλ μ©μ΄
- 1.3. Motivation : λκΈ°
- 1.4. Applicability : μ μ©
- 1.5. Structure
- 1.6. Participants
- 1.7. Collaborations : νλ ₯
- 1.8. Consequences : κ²°λ‘
- 1.9. Implementation : ꡬν, μ μ©
- 1.10. Sample Code
- 1.11. Known Uses
- 1.12. Related Patterns
DeleteMe ) νμ¬ μ§νμ€ --μλ―Ό
1.1. Intent : μλ ¶
κ°μ²΄ μμ±μ μν μΈν°νμ΄μ€λ₯Ό μ μνλΌ, κ·Έλ μ§λ§ sub ν΄λμ€λ€μ΄ ꡬνμ¬νμ κ²°μ ν μ μλλ‘ νμ.
Factory Methodλ sub ν΄λμ€μ λν΄ κ΅¬ν μ¬νμ κ²°μ ν μ μκ² λ§λ λ€.
Factory Methodλ sub ν΄λμ€μ λν΄ κ΅¬ν μ¬νμ κ²°μ ν μ μκ² λ§λ λ€.
1.3. Motivation : λκΈ° ¶
Framework(μ΄ν Framework κ·Έλλ‘)λ κ°μ²΄μ¬μ΄μ κ΄κ²λ₯Ό μ μνκ³ , μ μ§νκΈ° μνμ¬ κ°μ ν΄λμ€λ€μ μ¬μ©νλ€. Frameworkλ μ’
μ’
μ΄λ¬ν ν΄λμ€λ€μ κΈ°λ°μΌλ‘ κ°μ²΄μ μμ±μ μ±
μμ μ§λ€.
μ¬λ¬ λ¬Έμλ₯Ό μ¬μ©μμκ² λ³΄μ¬μ€μ μλ μ΄ν리μΌμ΄μ
μ λν Frameworkμ λνμ¬ μκ°ν΄ 보μ. μ΄λ¬ν Frameworkμμ λκ°μ§μ μΆμνμ λν μμ μ, Applicationκ³Ό Documentν΄λμ€ μΌκ²μ΄λ€. μ΄ λ ν΄λμ€λ€ μΆμμ μ΄κ³ , ν΄λΌμ΄μΈνΈλ κ·Έλ€μ Applicationμ μλ§κ² λͺ
μΈ μ¬νμ ꡬνν΄μΌ νλ€. μλ₯Όλ€μ΄μ Drawing Applicationμ λ§λ€λ €λ©΄ μ°λ¦¬λ DrawingApplication κ³Ό DrawingDocument ν΄λμ€λ₯Ό ꡬνν΄μΌ νλ€. Applicationν΄λμ€λ Document ν΄λμ€λ₯Ό κ΄λ¦¬νλ€. κ·Έλ¦¬κ³ μ¬μ©μκ° Openμ΄λ Newλ₯Ό λ©λ΄μμ μ ννμμλ μ΄λ€μ μμ±νλ€.
Application(ν΄λμ€κ° μλ)λ§λ€λ μꡬλλ νΉλ³ν Documentμ λν Sub ν΄λμ€ κ΅¬νλλ¬Έμ, Application ν΄λμ€λ Domentμ Sub ν΄λμ€μ λν λ΄μ©μ μμΈ‘ν μκ° μλ€. Application ν΄λμ€λ μ€μ§ μλ‘μ΄ μ’
λ₯ Documentκ° λ§λ€μ΄ μ§λκ° μλλΌ, μλ‘μ΄ Document ν΄λμ€κ° λ§λ€μ΄ μ§λλ§ μ΄λ₯Ό λ€λ£°μ μλ κ²μ΄λ€. μ΄λ° μμ±μ λλ λ§μ΄λ€.:Frameworkλ λ°λμ ν΄λμ€μ κ΄ν΄μ λͺ
μν΄μΌ λμ§λ§, μ€μ μ μ°μμ ννν μ μκ³ μ€μ§ μΆμνλ λ΄μ© λ°μ λ€λ₯Όμ μλ€.
Factory Method ν¨ν΄μ μ΄μ λν ν΄κ²°μ±
μ μ μνλ€. κ·Έκ²μ Documentμ sub ν΄λμ€μ μμ±μ λν μ 보λ₯Ό μΊ‘μν μν€κ³ , Frameworkμ μΈλΆλ‘ μ΄λ° μ 보λ₯Ό μ΄λ μν€κ² νλ€.
Applicationμ Sub ν΄λμ€λ Applicationμμμ μΆμμ μΈ CreateDocument μνμ μ¬μ μ νκ³ , Document subν΄λμ€μκ² μ κ·Όν μ μκ² νλ€. Aplicationμ subν΄λμ€λ νλ² κ΅¬νλλ€. κ·Έλ° λ€μ κ·Έκ²μ Applicationμ μλ§μ Documentμ λνμ¬ κ·Έλ€μ ν΄λμ€κ° νΉλ³ν μ νμ μμ΄ κ΅¬νν μ μλ€. μ°λ¦¬λ CreateDocumentλ₯Ό νΈμΆνλ€. μλνλ©΄ κ°μ²΄μ μμ±μ λνμ¬ κ΄μ¬νκΈ° μν΄μ μ΄λ€.
1.4. Applicability : μ μ© ¶
Fatory Method ν¨ν΄μ μ΄λ΄λ μ¬μ©νλ€.
- ν΄λμ€κ° κ·Έκ²μ΄ μμ±νλ ν΄λμ€μ κ΄ν΄μ μμν μ μμλ
- ν΄λμ€κ° κ·Έκ²μ sub ν΄λμ€κ° κ°μ²΄ μμ±μ μ΅μ νλ₯Ό μν€κ³ μΆμλ
- ν΄λμ€κ° λͺκ°μ helper subν΄λμ€μκ² μ±
μμ μμνκ±°λ, λΉμ μ΄ helper subν΄λμ€μ κ΄ν μ 보λ₯Ό νΉμ±ν μν€κΈ°λ₯Ό μν λ
1.6. Participants ¶
- Product (Document)
- Factory Methodκ° μμ±νλ κ°μ²΄μ κ΄ν μΈν°νμ΄μ€λ₯Ό μ μνλ€.
- Factory Methodκ° μμ±νλ κ°μ²΄μ κ΄ν μΈν°νμ΄μ€λ₯Ό μ μνλ€.
- ConcreteProduct (MyDocument)
- Productμ μΈν°νμ΄μ€μ λν ꡬνμ¬νμ΄λ€.
- Productμ μΈν°νμ΄μ€μ λν ꡬνμ¬νμ΄λ€.
- Creator (Application)
- Procunt νμ κ°μ²΄λ₯Ό λ°ννλ Factory Methodλ₯Ό μ μΈνλ€. Creatorλ λν κΈ°λ³Έ ConcreteProductκ°μ²΄λ₯Ό λ°ννλ factory methodμ κ΄ν κΈ°λ³Έ ꡬνλ μ μλμ΄ μλ€.
- Productκ°μ²΄λ₯Ό λ§λ€κΈ°μν factory methodλ₯Ό νΈμΆνλ€.
- Procunt νμ κ°μ²΄λ₯Ό λ°ννλ Factory Methodλ₯Ό μ μΈνλ€. Creatorλ λν κΈ°λ³Έ ConcreteProductκ°μ²΄λ₯Ό λ°ννλ factory methodμ κ΄ν κΈ°λ³Έ ꡬνλ μ μλμ΄ μλ€.
- ConcreteCreator (MyApplication)
- ConcreteProductμ μΈμ€ν΄μ€λ₯Ό λ°ννκΈ° μν, factory methodλ₯Ό μ€λ²λΌμ΄λ(over ride) νλ€.
- ConcreteProductμ μΈμ€ν΄μ€λ₯Ό λ°ννκΈ° μν, factory methodλ₯Ό μ€λ²λΌμ΄λ(over ride) νλ€.
1.7. Collaborations : νλ ₯ ¶
Creatorλ factor methodκ° μ μλμ΄ μλ Creatorμ subν΄λμ€μκ² μμ§νλ€ κ·Έλμ Creatorλ CooncreteProductμ μ ν©ν μΈμ€ν΄μ€λ€μ λ°ννλ€.
1.8. Consequences : κ²°λ‘ ¶
DeleteMe) 'κ²°κ³Ό' λ 'κ²°λ‘ ' μ΄λ κ·Έκ² κ·Έκ±°μ§λ§. --; 'ν¨ν΄μ μ©κ²°κ³Ό' μ λ.
Factory methodλ λΉμ μ μ½λμμ λ§λ€μ΄μΌν Applicationμ΄ μꡬνλ ν΄λμ€μ λν κΈ°λ₯κ³Ό Frameworkκ° λ¬Άμ¬μΌν νμμ±μ μ κ±°νλ€. κ·Έ μ½λλ μ€μ§ Productμ μΈν°νμ΄μ€ λ§μ μ μνλ€.; κ·Έλμ μ΄λ ν ConcreteProductμ ν΄λμ€λΌλ μ μν μ μκ² νμ¬ μ€λ€.DeleteMe) μ κ²°κ³Όμ§. κ²°κ³Όλ μ μ©νμ μ»μμ μλ μ΄μ΅μ΄μ§λ§, νμ¬ μ΄κ²μ ν¨ν΄μ μ μ©ν μ½λλ₯Ό ꡬννκΈ° μ μ μ΄λ‘ μ λ°νμ λνμ¬ κ²°λ‘ μ§λ κ²μ΄λΌκ³ μκ°ν΄μ κ²°λ‘ μ΄λΌκ³ νμ. κ·Έλ₯ κ²°κ³Όλ λΆμ‘±νκ² κ°κ³ , "ν¨ν΄ μ μ© κ²°κ³Ό"보λ€λ "ν¨ν΄ μ μ© κ²°κ³Ό κ³ μ°°" μ΄λΌλ μλ―Έκ° κ°νκ±° κ°μλ°, κ·Έλ₯ κ²°λ‘ μΌλ‘ μΏ¨λ --;
DeleteMe λͺ¨νΈ
factory methodμ μ μ¬μ μΈ λ¨μ μ΄λΌκ³ νλ€λ©΄ ν΄λΌμ΄μΈνΈκ° μλ§λ λ¨μ§ νΉλ³ν ConcreteProductκ°μ²΄λ₯Ό λ§λ€κΈ°μν΄μ Creatorν΄λμ€μ subν΄λμ€λ₯Ό κ°μ§κ³ μμ΄μΌ νλ€λ κ²μΌκΊΌλ€. ν΄λΌμ΄μΈνΈκ° μ΄λ€ μμΌλ‘λ Creatorμ subν΄λμ€λ₯Ό λ§λ€λμ, subν΄λμ€λ₯Ό λ§λλ κ²μ체λ μ’λ€. νμ§λ§ ν΄λΌμ΄μΈνΈλ μ΄λ°κ²μ μ κ²½μΈ νμμμ΄ λ‘μ§ κ΅¬νμ μ κ²½μ μ¨μΌ νλ€.
factory methodμ μ μ¬μ μΈ λ¨μ μ΄λΌκ³ νλ€λ©΄ ν΄λΌμ΄μΈνΈκ° μλ§λ λ¨μ§ νΉλ³ν ConcreteProductκ°μ²΄λ₯Ό λ§λ€κΈ°μν΄μ Creatorν΄λμ€μ subν΄λμ€λ₯Ό κ°μ§κ³ μμ΄μΌ νλ€λ κ²μΌκΊΌλ€. ν΄λΌμ΄μΈνΈκ° μ΄λ€ μμΌλ‘λ Creatorμ subν΄λμ€λ₯Ό λ§λ€λμ, subν΄λμ€λ₯Ό λ§λλ κ²μ체λ μ’λ€. νμ§λ§ ν΄λΌμ΄μΈνΈλ μ΄λ°κ²μ μ κ²½μΈ νμμμ΄ λ‘μ§ κ΅¬νμ μ κ²½μ μ¨μΌ νλ€.
A potential disadvantage of factory methods is that clients might have to subclass the Creator class just to create a particular ConcreteProduct object. Subclassing is fine when the client has to subclass the Creator class anyway, but otherwise the client now must deal with another point of evolution.
μ, μμ Factory Method ν¨ν΄μ κ΄λ ¨ν λκ°μ§μ κ²°λ‘ μ μ΄μΌκΈ° νλ€.:
Here are two additional consequences of the Factory Method pattern:
Here are two additional consequences of the Factory Method pattern:
- μλΈ ν΄λμ€μ μν΅ ν΅λ‘ μ 곡(Provides hooks for subclasses.) Factory Methodλ₯Ό μ μ©ν ν΄λμ€μμ κ°μ²΄μ μμ±μ νμ μ§μ λ§λ€μ΄μ§λ κ°μ²΄μ λΉνμ¬ μ μ°νλ€. Factory Methodλ κ°μ²΄μ μμλ λ²μ μ μ 곡μ μνμ¬, subν΄λμ€μ μ°κ²°λ μ μλ€.(hookμ μλ―ΈμΈλ°, μ°κ²°λ‘ ν΄μνκ³ , κ·Έλ¦Όμ λ³΄κ³ μ΄ν΄ν΄μΌ νλ€.)
Ducumentμμ μμ Documentν΄λμ€λ factory methodμ ν΄λΉνλ, μλ£λ₯Ό μ΄λνκΈ° μν κΈ°λ³Έ νμΌ λ€μ΄μΌλ‘κ·Έλ₯Ό μμ±νλ CreateFileDialogμ΄ νΈμΆμ μ μν μ μλ€. κ·Έλ¦¬κ³ Document subν΄λμ€λ μ΄λ¬ν factory methodλ₯Ό μ€λ² λΌμ΄λ©ν΄μ λ§λ€κ³ μ νλ applicationμ νΉνλ νμΌ λ€μ΄μΌλ‘κ·Έλ₯Ό μ μν μ μλ€. μ΄λ¬ν κ²½μ°μ factory methodλ μΆμμ μ΄μ§ μλ€. νμ§λ§ μ¬λ°λ₯Έ κΈ°λ³Έ ꡬνμ μ 곡νλ€.
- ν΄λμ€ μμ κ΄κ²μ μνμ μΈ(λ³λ ¬μ μΈ) μ°κ²° μ 곡(Connects parallel class hierarchies.) μ¬νκΉμ§ factory methodλ μ€μ§ Creatorμμλ§ λΆλ¦¬λκ±Έ μκ°ν΄ μλ€. κ·Έλ μ§λ§ μ΄λ²μλ κ·Έλ¬ν κ²½μ°λ₯Ό λ°μ§λ κ²μ΄ μλλ€.; ν΄λΌμ΄μΈνΈλ μνμ (λ³λ ¬μ )μΈ ν΄λμ€κ° μμ κ΄κ³μμ factory methodμ μ μ©ν¨μ μ°Ύμμ μλ€.
λ³λ ¬ ν΄λμ€ μμμ ν΄λμ€κ° μ΄λ ν λ¬Έμ μ μ± μμ κ΄ν΄μ λ€λ₯Έ ν΄λμ€λ‘ λΆλ¦¬νκ³ , μ± μμ μμνλ κ²°κ³Όλ₯Ό μ΄λ‘νλ€. μ‘°μ ν μ μλ κ·Έλ¦Ό λν(graphical figures)λ€μ κ΄ν΄μ μκ°ν΄ 보μ.;κ·Έκ²μ λ§μ°μ€μ μνμ¬ λ»μμ μκ³ , μ겨μ§κ³ , νμ λ νλ€. κ·Έλ¬ν μνΈμμ©μ λν ꡬνμ μΈμ λ μ¬μ΄κ²λ§μ μλλ€. κ·Έκ²μ μμ£Ό λμ΄λλ ν΄λΉ λνμ μν μ 보μ 보κ΄κ³Ό μ λ°μ΄νΈλ₯Ό μꡬνλ€. κ·Έλμ μ΄λ° μ 보λ μνΈ μμ©νλ, κ°μ²΄μλ€κ° λ³΄κ΄ ν μλ§μ μλ€. κ²λ€κ° μλ‘λ€λ₯Έ κ°μ²΄μ κ²½μ° μλ‘λ€λ₯Έ μνμ μ 보λ₯Ό 보κ΄ν΄μΌ ν ν λ° λ§μ΄λ€. μλ₯Όλ€μλ©΄, text λͺ¨μμ΄ λ°λλ©΄ κ·Έκ²μ 곡백μ λ³νμν€μ§λ§, Line λͺ¨μμ λ릴λλ λμ μ μ΄λμΌλ‘ λͺ¨μμ λ°κΏμ μλ€.
μ΄λ¬ν μ νμμλ λͺ¨μμλ°λΌ, κ° μν μ λ°λΌ κ°μ²΄λ₯Ό λΆλ¦¬νλ κ²μ΄ λ μ’μ κ²μ΄κ³ , κ°μ νμλ‘νλ μνλ₯Ό μ μ§ ν΄μΌνλ€. μλ‘ λ€λ₯Έ λͺ¨μμ μλ‘λ€λ₯Έ Manipulatorμ subν΄λμ€λ₯Ό μ¬μ©ν΄μ μμ§μ¬μΌ νλ€.μ΄λ¬ν Manipulatorν΄λμ€μ μμμ λ³λ ¬μ μΌλ‘ μ΄λ£¨μ΄ μ§λ€. λ€μκ³Ό κ°μ λͺ¨μ κ°μ΄ λ§μ΄λ€.
Figureν΄λμ€λ CreateManipulatorλΌλ, μλ‘ μμ©νλ κ°μ²΄λ₯Ό μμ±ν΄ μ£Όλ factory methodμ΄λ€. Figureμ subν΄λμ€λ μ΄ λ©μλλ₯Ό μ€λ²λΌμ΄λ(override)ν΄μ κ·Έλ€μκ² μλ§λ Manipulator subν΄λμ€μ μΈμ€ν΄μ€λ₯Ό (λ§λ€μ΄, )λ°ννλ€. Figure ν΄λμ€λ μλ§λ κΈ°λ³Έ ManipulatorμΈμ€ν΄μ€λ₯Ό (λ§λ€μ΄,) λ°ννκΈ° μν κΈ°λ³Έ CreateManipulatorλ₯Ό ꡬννμ κ²μ΄λ€. κ·Έλ¦¬κ³ Figureμ subν΄λμ€λ κ°λ¨ν μ΄λ¬ν κΈ°λ³Έκ°λ€μ μμνμλ€. Figureν΄λμ€ λ€μ μμ κ³Ό κ΄κ³μλ Manipulatorλ€μ λνμ¬ μ κ²½ μΈνμκ° μλ€. κ·Έλ¬λ―λ‘ μ΄λ€μ κ΄κ³λ λ³λ ¬μ μ΄ λλ€.
Factory Methodκ° λκ²μ ν΄λμ€μ μμ κ΄κ³μμ μ΄λ»κ² μ΄λ¬ν μ°κ²°κ³Όμ μ μ μνλμ§ μ£Όλͺ©νλΌ. κ·Έκ²μ μλ‘ κ³ μ μ κΈ°λ₯μ λΆμ¬μν€λ μμ
μ νλ€.
1.9. Implementation : ꡬν, μ μ© ¶
Factory Methodν¨ν΄μ΄ μ μ©λ λ λ°μν μ μλ λ¬Έμ μ κ΄ν΄μ μκ°ν΄ 보μ.:
- λκ°μ§μ 컀λ€λ λ³μ. Factory Method ν¨ν΄μμ λκ°μ§μ μ€μν λ³μλ 첫λ²μ§Έ Creator ν΄λμ€κ° κ°μ ν΄λμ€μ΄κ³ , κ·Έκ²μ μ μΈμ νμ§λ§ ꡬνμ΄ μλ λμ κ²½μ΄ λλ²μ§Έλ‘ Creatorκ° concrete ν΄λμ€μ΄κ³ , factor methodλ₯Ό μν κΈ°λ³Έ ꡬνμ μ 곡ν΄μΌ νλ κ²½μ°. κΈ°λ³Έ ꡬνμ΄ μ μλμ΄ μλ κ°μ ν΄λμ€λ₯Ό κ°μ§λ건 κ°λ₯νμ§λ§ μ΄κ±΄ μΌλ°μ μ΄μ§ λͺ»νλ€.
첫λ²μ§Έ κ²½μ°λ μ½λκ° κ΅¬νλ subν΄λμ€λ₯Ό μꡬνλ€. μλνλ©΄, μ λΉν κΈ°λ³Έ ꡬν μ¬νμ΄ μκΈ°λλ¬Έμ΄λ€. μμν μ μλ ν΄λμ€μ κ΄ν μ½λλ₯Ό ꡬννλ€λ κ²μ λλ λ§μ΄λ€. λλ²μ§Έκ²½μ°μλ μ μ°μ±μ μν΄μ concrete Creatorκ° factory method λ¨Όμ μ¬μ©ν΄μΌ νλ κ²½μ°μ΄λ€. λ€μκ³Ό κ°μ κ·μΉμ μ΄μΌκΈ° νλ€."μλ‘ λΆλ¦¬λ μν λ°©λ²μΌλ‘, κ°μ²΄λ₯Ό μμ±νλΌ, κ·Έλ κ² ν΄μ subν΄λμ€λ€μ κ·Έλ€μ΄ μμ±λ μ μλ λ°©λ²μ μ€λ²λΌμ΄λ(override)ν μ μλ€." μ΄ κ·μΉμ subν΄λμ€μ λμμ΄λλ€μ΄ νμνλ€λ©΄, κ·Έλ€ κ³ μ μ κ°μ²΄μ κ΄λ ¨ν κΈ°λ₯μΌλ‘ subν΄λμ€ λ¨μκ² λ°κΏμ μμμ μλ―Ένλ€.
- Parameterized factory methods(κ·Έλλ‘ μ΄λ€.) Factory Methodν¨ν΄μμ λ λ€λ₯Έ λ³μλΌλ©΄ λ€μν μ’
λ₯μ productλ₯Ό μ¬μ©ν λ μ΄λ€. factory methodλ μμ±λ κ°μ²΄μ μ’
λ₯λ₯Ό νμΈνλ μΈμλ₯Ό κ°μ§κ³ μλ€. λͺ¨λ κ°μ²΄μ λνμ¬ factory methodλ μλ§ Product μΈν°νμ΄μ€λ₯Ό 곡μ ν κ²μ΄λ€. Documentμμ μμ, Applicationμ μλ§λ λ€μν μ’
λ₯μ Documentλ₯Ό μ§μν΄μΌ νλ€. λΉμ μ CreateDocumentμκ² documentμμ±μ μ’
λ₯λ₯Ό νλ³νλ μΈμ νλλ₯Ό λκΈ΄λ€.
Unidraw κ·Έλν½ μλν° Frameworkλ λμ€ν¬μ μ μ₯λ κ°μ²΄μ μ¬ μμ±μ μνμ¬ μ΄λ¬ν μ κ·Όλ²μ μ¬μ©νκ³ μλ€. Unidrawλ factory methodλ₯Ό μ΄μ©ν Creator ν΄λμ€κ° μλ³μλ₯Ό κ°μ§κ³ μλλ‘ μ μν΄ λμλ€. μ΄ ν΄λμ€ μλ³μλ μ ν©ν ν΄λμ€λ₯Ό κΈ°μ νκ³ μλ€. Unidrawκ° κ°μ²΄λ₯Ό λμ€ν¬μ μ μ₯ν λ μ΄ ν΄λμ€ μλ³μκ° μΈμ€ν΄μ€ λ³μμ μ΄λ€κ² 보λ€λ μμ κΈ°λ‘ λλ κ²μ΄λ€. κ·Έλ¦¬κ³ λμ€ν¬μμ λ€μ κ°μ²΄λ€μ΄ μμ±λ λ μ΄ μλ³μλ₯Ό μμ κ°μ₯ λ¨Όμ μ½λλ€.
ν΄λμ€ μλ³μλ₯Ό μ½κ³ μ Frameworkλ μλ³μλ₯Ό Createμκ² λκΈ°λ©΄μ νΈμΆνλ€. Createλ μ λΉν ν΄λμ€λ₯Ό μ°Ύκ³ , κ·Έκ²μ κ°μ²΄μ μμ±μ μ¬μ©νλ€. λ§μ§λ§μΌλ‘ Createλ κ°μ²΄μ Read μνμ νΈμΆνμ¬ λμ€ν¬μ μ 보λ₯Ό μ μ₯νκ³ , μΈμ€ν΄μ€ λ³μλ€μ μ΄κΈ°ν νλ€.
Parameterized factory methodλ Productλ₯Ό μμλ°μ MyProductμ YourProductμμμμΌλ°μ μΌλ‘ λ€μκ³Ό κ°μ ννλ₯Ό κ°μ§λ€.
~cpp class Creator { public: virtual Product* Create(ProductId); }; Product* Creator::Create (ProductId id) { if (id == MINE) return new MyProduct; if (id == YOURS) return new YourProduct; // λ¨μ productμ μ’ λ₯μ λ°λ³΅ return 0; }
Parameterized factory method λ Creatorκ° μμ±νλ productλ₯Ό μ νμ μΌλ‘ νμ₯νκ³ , λ³νμν€λλ°, μ½κ² λ§λ€μ΄ μ€λ€. κ·Έλ¦¬κ³ μλ‘μ΄ μλ³μλ‘ μλ‘μ΄ μ’ λ₯μ productλ₯Ό λμ νκ³ λ, μλ‘λ€λ₯Έ productμ μλ³μλ₯Ό μ°κ΄μν¬μλ μλ€.
μλ₯Ό λ€μ΄μ subν΄λμ€ MyCreatorλ MyProductμ YouProductλ₯Ό λ°κΎΈκ³ , μλ‘μ΄ TheirProduct Subν΄λμ€λ₯Ό μ§μν μ μλ€.
~cpp Product* MyCreator::Create (ProductId id) { if (id == YOURS) return new MyProduct; if (id == MINE) return new YourProduct; // YouProductμ MyProduct κ΅ν if (id == THEIRS) return new TheirProduct; // μλ‘μ΄ product μΆκ° return Creator::Create(id); // λ§μ½ λͺ¨λκ° μ€ν¨νλ©΄ κΈ°λ³Έ μμ±μλ₯Ό λΆλ₯Έλ€. }
DeleteMe λͺ¨νΈ)λ§μ§λ§ λΆλΆμμ λΆλͺ¨ ν΄λμ€μ μΈμλ₯Ό μννλ κ²μ μ£Όλͺ©ν΄λΌ. MyCreator::Createλ μ€μ§ YOURS, MINE, THEIRSλ₯Ό μ‘μμ μκ³ , λΆλͺ¨ν΄λμ€λ μ‘μ§ λͺ»νλ€. λ€λ₯Έ ν΄λμ€λ μ΄λ₯Ό μννμ§ λͺ»νλ€. κ·Έλ¬λ―λ‘, MyCreatorλ μμ±λ productμ ν μ’ λ₯λ₯Ό νμ₯νκ³ , κ·Έκ²μ μμ±μ λν μ± μμ μ°κΈ°νλ€. νμ§λ§, productκ° κ·Έκ²μ λΆλͺ¨μΈκ²μ μ λ€.
- μΈμ΄ κ·μΉμμμ λ³μμ μ΄μ(Language-specific variants and issues) λ€λ₯Έ μΈμ΄μ¬μμλ μ’λ λ€λ₯Έ λ°©μμΌλ‘ λ€λ₯Έ μ μ°¨λ‘ κ΅¬νλ κ²μ΄λ€.
Smalltalkνλ‘κ·Έλλ¨Έλ€μ μ’ μ’ κ΅¬μ²΄μ μΌλ‘ ꡬνλμ΄ μλ κ°μ²΄μ ν΄λμ€λ₯Ό λ°ννλ λ©μλλ₯Ό μ¬μ©νλ€. Creatorμ factory methodλ μ΄λ¬ν κ°μ μ¬μ©νμ¬ productλ₯Ό λ§λ€μ΄ λ΄κ³ , ConcreteCreatorλ μλ§ μ μ₯νκ±°λ, μ΄λ¬ν κ°μΌ κ³μ°μ μννλ€. μ΄λ¬ν κ²°κ³Όλ ꡬνλμ΄ μλ ConcreteProductμ νμ μνμ¬ λ°μΈλ© μ‘°μ°¨ λμ€μ νκ² λλ€.
Smalltalk λ²μ μ Document μμ λ documentClass λ©μλλ₯Ό Applicationμμ μ μν μ μλ€. documentClass λ©μλλ μλ£λ₯Ό νννκΈ° μν μ λΉν Document ν΄λμ€λ₯Ό λ°ννλ€. MyApplicationμμ documentClassμ ꡬνμ MyDocument ν΄λμ€λ₯Ό λ°ννλ κ²μ΄λ€. κ·Έλμ Applicationμμ ν΄λμ€λ μ΄λ κ² μκ²Όκ³
~cpp clientMethod document := self documentClass new. documentClass self subclassResponsibility
~cpp documentClass ^ MyDocument
C++μμ Factory methodλ νμ κ°μν¨μμ΄κ³ , μ’
μ’
μμ κ°μ ν¨μμ΄λ€. Creatorμ μμ±μ λ΄λΆμμ factory methodsμ νΈμΆμ κ²°μ½ μ’μ§ λͺ»νκ² μΌκΉ? κ·Έλ¬ν factory methodλ ConcreteCreatorμμ μ‘΄μ¬νκ³ , μμ§ νμ±ν λμ§ μμλ€.
You can avoid this by being careful to access products solely through accessor operations that create the product on demand. Instead of creating the concrete product in the constructor, the constructor merely initializes it to 0. The accessor returns the product. But first it checks to make sure the product exists, and if it doesn't, the accessor creates it. This technique is sometimes called lazy initialization. The following code shows a typical implementation:
~cpp class Creator { public: Product* GetProduct(); protected: virtual Product* CreateProduct(); private: Product* _product; }; Product* Creator::GetProduct () { if (_product == 0) { _product = CreateProduct(); } return _product; }
- Using templates to avoid subclassing. As we've mentioned, another potential problem with factory methods is that they might force you to subclass just to create the appropriate Product objects. Another way to get around this in C++ is to provide a template subclass of Creator that's parameterized by the Product
~cpp class: class Creator { public: virtual Product* CreateProduct() = 0; }; template class StandardCreator: public Creator { public: virtual Product* CreateProduct(); }; template Product* StandardCreator::CreateProduct () { return new TheProduct; }
~cpp class MyProduct : public Product { public: MyProduct(); // ... }; StandardCreator myCreator;
- Naming conventions. It's good practice to use naming conventions that make it clear you're using factory methods. For example, the MacApp Macintosh application framework App89 always declares the abstract operation that defines the factory method as Class* DoMakeClass(), where Class is the Product class.
1.10. Sample Code ¶
The function CreateMaze (page 84) builds and returns a maze. One problem with this function is that it hard-codes the classes of maze, rooms, doors, and walls. We'll introduce factory methods to let subclasses choose these components.
First we'll define factory methods in MazeGame for creating the maze, room, wall, and door objects:
Each factory method returns a maze component of a given type. MazeGame provides default implementations that return the simplest kinds of maze, rooms, walls, and doors.
~cpp class MazeGame { public: Maze* CreateMaze(); // factory methods: virtual Maze* MakeMaze() const { return new Maze; } virtual Room* MakeRoom(int n) const { return new Room(n); } virtual Wall* MakeWall() const { return new Wall; } virtual Door* MakeDoor(Room* r1, Room* r2) const { return new Door(r1, r2); } };
Now we can rewrite CreateMaze to use these factory methods:
Different games can subclass MazeGame to specialize parts of the maze. MazeGame subclasses can redefine some or all of the factory methods to specify variations in products. For example, a BombedMazeGame can redefine the Room and Wall products to return the bombed varieties:
An EnchantedMazeGame variant might be defined like this:
~cpp Maze* MazeGame::CreateMaze () { Maze* aMaze = MakeMaze(); Room* r1 = MakeRoom(1); Room* r2 = MakeRoom(2); Door* theDoor = MakeDoor(r1, r2); aMaze->AddRoom(r1); aMaze->AddRoom(r2); r1->SetSide(North, MakeWall()); r1->SetSide(East, theDoor); r1->SetSide(South, MakeWall()); r1->SetSide(West, MakeWall()); r2->SetSide(North, MakeWall()); r2->SetSide(East, MakeWall()); r2->SetSide(South, MakeWall()); r2->SetSide(West, theDoor); return aMaze; }
~cpp class BombedMazeGame : public MazeGame { public: BombedMazeGame(); virtual Wall* MakeWall() const { return new BombedWall; } virtual Room* MakeRoom(int n) const { return new RoomWithABomb(n); } };
~cpp class EnchantedMazeGame : public MazeGame { public: EnchantedMazeGame(); virtual Room* MakeRoom(int n) const { return new EnchantedRoom(n, CastSpell()); } virtual Door* MakeDoor(Room* r1, Room* r2) const { return new DoorNeedingSpell(r1, r2); } protected: Spell* CastSpell() const; };
1.11. Known Uses ¶
Factory methods pervade toolkits and frameworks. The preceding document example is a typical use in MacApp and ET++ WGM88. The manipulator example is from Unidraw.
Class View in the Smalltalk-80 Model/View/Controller framework has a method defaultController that creates a controller, and this might appear to be a factory method Par90. But subclasses of View specify the class of their default controller by defining defaultControllerClass, which returns the class from which defaultController creates instances. So defaultControllerClass is the real factory method, that is, the method that subclasses should override.
A more esoteric example in Smalltalk-80 is the factory method parserClass defined by Behavior (a superclass of all objects representing classes). This enables a class to use a customized parser for its source code. For example, a client can define a class SQLParser to analyze the source code of a class with embedded SQL statements. The Behavior class implements parserClass to return the standard Smalltalk Parser class. A class that includes embedded SQL statements overrides this method (as a class method) and returns the SQLParser class.
The Orbix ORB system from IONA Technologies ION94 uses Factory Method to generate an appropriate type of proxy (see Proxy (207)) when an object requests a reference to a remote object. Factory Method makes it easy to replace the default proxy with one that uses client-side caching, for example.
1.12. Related Patterns ¶
Abstract Factory (87) is often implemented with factory methods. The Motivation example in the Abstract Factory pattern illustrates Factory Method as well.
Factory methods are usually called within Template Methods (325). In the document example above, NewDocument is a template method.
Prototypes (117) don't require subclassing Creator. However, they often require an Initialize operation on the Product class. Creator uses Initialize to initialize the object. Factory Method doesn't require such an operation.