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.