๊ด€๋ฆฌ ๋ฉ”๋‰ด

deVlog

[๋””์ž์ธ ํŒจํ„ด] ์ƒ์„ฑํŒจํ„ด - Factory Method Pattern (ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ ํŒจํ„ด) ๋ณธ๋ฌธ

๐Ÿ› ๏ธ Software Architecture/Design Pattern

[๋””์ž์ธ ํŒจํ„ด] ์ƒ์„ฑํŒจํ„ด - Factory Method Pattern (ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ ํŒจํ„ด)

์€๋ฃจ๋ฐ 2024. 12. 4. 12:55

๋ชฉ์ฐจ

     

    ๐Ÿ“‡ ๊ฐœ์š”

    Factory ํŒจํ„ด์€ ๊ฐ์ฒด ์ƒ์„ฑ๊ณผ ๊ด€๋ จ๋œ ๋””์ž์ธ ํŒจํ„ด์ด๋‹ค.

    Simple Factory ํŒจํ„ด์€ ๊ฐ์ฒด ์ƒ์„ฑ ์—ญํ• ์„ ๋‹ด๋‹นํ•˜๋ฉด์„œ ๊ฐ ํด๋ผ์ด์–ธํŠธ์—์„œ ๊ตฌํ˜„ ํด๋ž˜์Šค์— ์ง์ ‘ ์˜์กดํ•˜์ง€ ์•Š๋„๋ก ๋ถ„๋ฆฌํ•œ๋‹ค.

    ํ•˜์ง€๋งŒ "์ƒˆ๋กœ์šด ํด๋ž˜์Šค๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ์„ ๋•Œ Factory ํด๋ž˜์Šค๋ฅผ ์ˆ˜์ •ํ•ด์•ผ ํ•œ๋‹ค"๋Š” ํ•œ๊ณ„๊ฐ€ ์žˆ๋‹ค.

    ๊ธฐ์กด ์ฝ”๋“œ์˜ ๋ณ€๊ฒฝ ์—†์ด ํ™•์žฅํ•˜๊ธฐ ์œ„ํ•œ ๋””์ž์ธ ํŒจํ„ด์ด ๋ฐ”๋กœ Factory Method ํŒจํ„ด์ด๋‹ค.

     

    • ์ƒ์„ฑ ํŒจํ„ด ์ค‘ ํ•˜๋‚˜๋กœ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ๋•Œ ์–ด๋–ค ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค ์ง€ ์„œ๋ธŒ ํด๋ž˜์Šค์—์„œ ๊ฒฐ์ •ํ•œ๋‹ค.
    • ์ฆ‰, ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ์„ ์„œ๋ธŒ ํด๋ž˜์Šค์—๊ฒŒ ์œ„์ž„ํ•œ๋‹ค.
    • ๋ถ€๋ชจ ์ถ”์ƒ ํด๋ž˜์Šค๋Š” ์ธํ„ฐํŽ˜์ด์Šค์—๋งŒ ์˜์กดํ•˜๊ณ  ์‹ค์ œ๋กœ ์–ด๋–ค ๊ตฌํ˜„ ํด๋ž˜์Šค๋ฅผ ํ˜ธ์ถœํ•  ์ง€๋Š” ์„œ๋ธŒ ํด๋ž˜์Šค์—์„œ ๊ตฌํ˜„ํ•œ๋‹ค.
    • ์ƒˆ๋กœ์šด ๊ตฌํ˜„ ํด๋ž˜์Šค๊ฐ€ ์ถ”๊ฐ€๋˜์–ด๋„ ๊ธฐ์กด Factory ์ฝ”๋“œ์˜ ์ˆ˜์ • ์—†์ด ์ƒˆ๋กœ์šด Factory ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ๋œ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ๋‹ค.

     

     

    ๐Ÿ‘ฉ๐Ÿป‍๐Ÿ’ป ์ฝ”๋“œ๋กœ ์•Œ์•„๋ณด์ž

    // ํฌ๋ฆฌ์—์ดํ„ฐ ํด๋ž˜์Šค๋Š” ์ œํ’ˆ ํด๋ž˜์Šค์˜ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•˜๋Š” ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ๋ฅผ ์„ ์–ธํ•ฉ๋‹ˆ๋‹ค.
    abstract class Dialog {
    
        // ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ (์ž์‹ ํด๋ž˜์Šค๊ฐ€ ์˜ค๋ฒ„๋ผ์ด๋“œ ํ•ด์•ผ ํ•จ)
        abstract Button createButton();
    
        // ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ์—์„œ ๋ฐ˜ํ™˜๋œ ์ œํ’ˆ ๊ฐ์ฒด์— ์˜์กดํ•˜๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง
        public void render() {
            // ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์ œํ’ˆ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ
            Button okButton = createButton();
            // ์ƒ์„ฑ๋œ ์ œํ’ˆ์„ ์‚ฌ์šฉ
            okButton.onClick(() -> System.out.println("Dialog closed"));
            okButton.render();
        }
    }
    
    // ๊ตฌ์ƒ ํฌ๋ฆฌ์—์ดํ„ฐ: WindowsDialog
    class WindowsDialog extends Dialog {
        @Override
        Button createButton() {
            return new WindowsButton();
        }
    }
    
    // ๊ตฌ์ƒ ํฌ๋ฆฌ์—์ดํ„ฐ: WebDialog
    class WebDialog extends Dialog {
        @Override
        Button createButton() {
            return new HTMLButton();
        }
    }
    
    // ์ œํ’ˆ ์ธํ„ฐํŽ˜์ด์Šค: Button
    interface Button {
        void render();        // ๋ฒ„ํŠผ์„ ๋ Œ๋”๋ง
        void onClick(Runnable action); // ํด๋ฆญ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ์„ค์ •
    }
    
    // ๊ตฌ์ƒ ์ œํ’ˆ: WindowsButton
    class WindowsButton implements Button {
        @Override
        public void render() {
            System.out.println("Rendering a Windows-style button.");
        }
    
        @Override
        public void onClick(Runnable action) {
            System.out.println("Binding a native OS click event.");
            action.run();
        }
    }
    
    // ๊ตฌ์ƒ ์ œํ’ˆ: HTMLButton
    class HTMLButton implements Button {
        @Override
        public void render() {
            System.out.println("Rendering an HTML button.");
        }
    
        @Override
        public void onClick(Runnable action) {
            System.out.println("Binding a web browser click event.");
            action.run();
        }
    }
    
    // ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ํด๋ž˜์Šค
    class Application {
        private Dialog dialog;
    
        // ํ˜„์žฌ ์„ค์ • ๋˜๋Š” ํ™˜๊ฒฝ ์„ค์ •์— ๋”ฐ๋ผ ํฌ๋ฆฌ์—์ดํ„ฐ์˜ ์œ ํ˜•์„ ์„ ํƒ
        public void initialize() {
            String configOS = readApplicationConfigFile();
    
            if ("Windows".equalsIgnoreCase(configOS)) {
                dialog = new WindowsDialog();
            } else if ("Web".equalsIgnoreCase(configOS)) {
                dialog = new WebDialog();
            } else {
                throw new RuntimeException("Error! Unknown operating system.");
            }
        }
    
        // ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ง„์ž…์ 
        public void main() {
            initialize();
            dialog.render();
        }
    
        // ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ํ™˜๊ฒฝ์„ค์ •์„ ์ฝ์–ด์˜ค๋Š” ๋ฉ”์„œ๋“œ (์˜ˆ์‹œ์šฉ)
        private String readApplicationConfigFile() {
            // ์‹ค์ œ ํ™˜๊ฒฝ์„ค์ •์„ ์ฝ๋Š” ๋กœ์ง์ด ๋“ค์–ด๊ฐ€์•ผ ํ•จ
            // ์—ฌ๊ธฐ์„œ๋Š” ์˜ˆ์‹œ๋กœ Windows ๋ฐ˜ํ™˜
            return "Windows";
        }
    
        public static void main(String[] args) {
            Application app = new Application();
            app.main();
        }
    }

     

     

     

    โ˜˜๏ธ ์žฅ/๋‹จ์ 

    ์žฅ์ 

    • ํฌ๋ฆฌ์—์ดํ„ฐ์™€ ๊ตฌ์ƒ ์ œํ’ˆ๋“ค์ด ๋‹จ๋‹จํ•˜๊ฒŒ ๊ฒฐํ•ฉ๋˜์ง€ ์•Š๋„๋ก ํ•  ์ˆ˜ ์žˆ๋‹ค. (์ œํ’ˆ ์ธํ„ฐํŽ˜์ด์Šค์— ์˜์กดํ•˜๊ธฐ ๋•Œ๋ฌธ)
    • ๋‹จ์ผ ์ฑ…์ž„ ์›์น™(SRP) : ์ œํ’ˆ ์ƒ์„ฑ ์ฝ”๋“œ๋ฅผ ํ”„๋กœ๊ทธ๋žจ์˜ ํ•œ ์œ„์น˜๋กœ ์ด๋™ํ•˜์—ฌ ์ฝ”๋“œ๋ฅผ ๋” ์‰ฝ๊ฒŒ ์œ ์ง€๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ๊ฐœ๋ฐฉ/ํ์‡„ ์›์น™(OCP) : ๊ธฐ์กด ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๋ฅผ ํ›ผ์†ํ•˜์ง€ ์•Š๊ณ  ์ƒˆ๋กœ์šด ์œ ํ˜•์˜ ์ œํ’ˆ๋“ค์„ ํ”„๋กœ๊ทธ๋žจ์— ๋„์ž…ํ•  ์ˆ˜ ์žˆ๋‹ค.

    ๋‹จ์ 

    • ํŒจํ„ด์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ๋งŽ์€ ์ƒˆ๋กœ์šด ์ž์‹ ํด๋ž˜์Šค๋“ค์„ ๋„์ž…ํ•ด์•ผ ํ•˜๋ฏ€๋กœ ์ฝ”๋“œ๊ฐ€ ๋” ๋ณต์žกํ•ด์งˆ ์ˆ˜ ์žˆ๋‹ค.

     

    ๐Ÿ”„ ๋‹ค๋ฅธ ํŒจํ„ด๊ณผ์˜ ๊ด€๊ณ„

     

     

     

     

     

    ๐Ÿ“‹ ์ฐธ๊ณ