Publish:

ํƒœ๊ทธ:

์นดํ…Œ๊ณ ๋ฆฌ:

์ปดํฌ์ง€ํŠธ ํŒจํ„ด(Composite pattern)

์ปดํฌ์ง€ํŠธ ํŒจํ„ด์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ณ , ๋„์ž… ์ „๊ณผ ํ›„์˜ ์ฐจ์ด์ ์„ ์•Œ์•„๋ด…๋‹ˆ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ตฌํ˜„๋œ ๋ฉ”๋‰ด ์ถœ๋ ฅ ํ”„๋กœ๊ทธ๋žจ์ด ์žˆ๋‹ค.

1
2
3
4
5
6
7
  [ ๋ฉ”์ธ ๋ฉ”๋‰ด ]
  1. ๊ณผ์ œ
  2. ๊ฒŒ์‹œ๊ธ€
  3. ํšŒ์›
  4. ๊ฐ€์ž…์ธ์‚ฌ
  5. ๋„์›€๋ง
  0. ์ข…๋ฃŒ

๋ฉ”์ธ ๋ฉ”๋‰ด์—์„œ ํ•ด๋‹น ๋ฒˆํ˜ธ๋ฅผ ๋ˆ„๋ฅด๋ฉด ์„œ๋ธŒ๋ฉ”๋‰ด๊ฐ€ ์ถœ๋ ฅ๋œ๋‹ค. ์˜ˆ๋ฅผ๋“ค์–ด ์‚ฌ์šฉ์ž๋กœ ๋ถ€ํ„ฐ 2๋ฅผ ์ž…๋ ฅ๋ฐ›์•„ ๊ฒŒ์‹œ๊ธ€ ๋ฉ”๋‰ด๋กœ ๋“ค์–ด๊ฐ€๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ๋ฉ”๋‰ด๊ฐ€ ์ถœ๋ ฅ๋œ๋‹ค.

1
2
3
4
5
6
7
  [ ๊ฒŒ์‹œ๊ธ€ ]
  1. ๋“ฑ๋ก
  2. ์กฐํšŒ
  3. ๋ณ€๊ฒฝ
  4. ์‚ญ์ œ
  5. ๋ชฉ๋ก
  0. ์ด์ „

Before

๊ฐ๊ฐ์˜ ๋ฉ”๋‰ด ํด๋ž˜์Šค์— ์ž…๋ ฅ์„ ๋ฐ›๋Š” ์†Œ์Šค์ฝ”๋“œ๊ฐ€ ์กด์žฌํ•˜๊ณ  ๊ทธ ์ž…๋ ฅ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ณผ์ •๋„ ๊ฐ๊ฐ์˜ ๋ฉ”๋‰ด ํด๋ž˜์Šค์— ๊ตฌํ˜„๋˜์–ด ์žˆ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
  public class MainMenu {
  
      ...
  
    Menu assignmentMenu = new AssignmentMenu("๊ณผ์ œ", this.prompt);
    Menu boardMenu = new BoardMenu("๊ฒŒ์‹œ๊ธ€", this.prompt);
    Menu greetingMenu = new BoardMenu("๊ฐ€์ž…์ธ์‚ฌ", this.prompt);
    Menu memberMenu = new MemberMenu("ํšŒ์›", this.prompt);
    Menu helpMenu = new HelpMenu("๋„์›€๋ง", this.prompt);
    
    printMenu(); // ๋ฉ”์ธ๋ฉ”๋‰ด ์ถœ๋ ฅ
  
    while(true) {
    String input = this.prompt.input("๋ฉ”์ธ> ");

      switch (input) {
        case "1":
          assignmentMenu.execute(prompt);
          break;
        case "2":
          boardMenu.execute(prompt);
          break;
        case "3":
          memberMenu.execute(prompt);
          break;
        case "4":
          greetingMenu.execute(prompt);
          break;
        case "5":
          helpMenu.execute(prompt);
          break;
        case "0":
          System.out.println("์ข…๋ฃŒํ•ฉ๋‹ˆ๋‹ค.");
          return;
        case "menu":
          this.printMenu();
          break;
        default:
          System.out.println("๋ฉ”๋‰ด ๋ฒˆํ˜ธ๊ฐ€ ์˜ณ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.");
      }
    } 
  }

BoardMenu.class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
public class BoardMenu {

  public void execute(Prompt prompt) {
  
      ...

    Board[] boards = new Board[3]; // ๊ฒŒ์‹œ๊ธ€ ์ €์žฅํ•  ๋ฐฐ์—ด
    int length = 0; // ํ˜„์žฌ ๊ฒŒ์‹œ๊ธ€ ์ €์žฅ ์ธ๋ฑ์Šค

    this.printMenu(); // ์„œ๋ธŒ๋ฉ”๋‰ด ์ถœ๋ ฅ

    while (true) {
      String input = prompt.input("๋ฉ”์ธ/%s> ", this.title);

      switch (input) {
        case "1":
          this.add();
          break;
        case "2":
          this.view();
          break;
        case "3":
          this.modify();
          break;
        case "4":
          this.delete();
          break;
        case "5":
          this.list();
          break;
        case "0":
          return;
        case "menu":
          this.printMenu();
          break;
        default:
          System.out.println("๋ฉ”๋‰ด ๋ฒˆํ˜ธ๊ฐ€ ์˜ณ์ง€ ์•Š์Šต๋‹ˆ๋‹ค!");
      }
    }

    void add () {
      // ๊ฒŒ์‹œ๊ธ€ ๋“ฑ๋ก  
    }

    void list () {
      // ๊ฒŒ์‹œ๊ธ€ ๋ชฉ๋ก
    }

    void view () {
      // ๊ฒŒ์‹œ๊ธ€ ์ƒ์„ธ์กฐํšŒ  
    }

    void modify () {
      // ๊ฒŒ์‹œ๊ธ€ ์ˆ˜์ •
    }

    void delete () {
      // ๊ฒŒ์‹œ๊ธ€ ์‚ญ์ œ
    }
  }
}

์œ„ ์†Œ์Šค์ฝ”๋“œ ์ฒ˜๋Ÿผ switch ๋ฌธ์œผ๋กœ ์ž…๋ ฅ ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ๋ถ„๊ธฐ์ฒ˜๋ฆฌ๋ฅผ ๊ฐ ๋ฉ”๋‰ด ํด๋ž˜์Šค๋งˆ๋‹ค ์‹œํ–‰ํ•˜๊ณ  ์žˆ๋‹ค. ์ƒˆ๋กœ์šด ๋ฉ”๋‰ด๊ฐ€ ์ถ”๊ฐ€๋  ๋•Œ๋งˆ๋‹ค MainMenu ์— ์„œ๋ธŒ๋ฉ”๋‰ด ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•ด์•ผํ•˜๊ณ  case ๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ํ˜„์žฌ ์ฝ”๋“œ๋Š” ๋ชจ๋“  ์„œ๋ธŒ๋ฉ”๋‰ด ํด๋ž˜์Šค๊ฐ€ ์ค‘๋ณต ์ฝ”๋“œ๋ฅผ ๋‹ค์ˆ˜ ํฌํ•จํ•˜๊ณ  ์žˆ๋‹ค. (switch ๋กœ ์ž…๋ ฅ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ถ€๋ถ„, CRUD ๊ธฐ๋Šฅ) ๋˜ํ•œ ๋ฉ”๋‰ดํด๋ž˜์Šค๊ฐ€ ์„œ๋กœ ๊ณ„์ธต๊ตฌ์กฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Œ์—๋„, ์ด๊ฒƒ์ด ์ฝ”๋“œ์ƒ์— ์ž˜ ํ‘œํ˜„์ด ๋˜์ง€ ์•Š๋Š”๋‹ค.

๋ฐ์ดํ„ฐ ๊ทธ ์ž์ฒด๋ฅผ ํ•ธ๋“ค๋ง ํ•˜๋Š” ์†Œ์Šค์ฝ”๋“œ๋Š” ์œ ์ง€๋ณด์ˆ˜ํ•˜๊ธฐ ํž˜๋“ค๊ณ  ๊ฐ์ฒด์ง€ํ–ฅ ํŒจ๋Ÿฌ๋‹ค์ž„๊ณผ๋Š” ๋งž์ง€ ์•Š๋‹ค. ์ปดํฌ์ง€ํŠธ ํŒจํ„ด์€ SOLID ๊ฐ์ฒด์ง€ํ–ฅ ์›๋ฆฌ ์ค‘ OCP(Open/Closed Principle) ๋ฅผ ๋งŒ์กฑํ•œ๋‹ค.


After

๊ธฐ์กด์˜ switch ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ž…๋ ฅ ๋ฐ›์•„์„œ ๋ฉ”๋‰ด๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋ฐฉ์‹์ด ์•„๋‹Œ, ๋ฉ”๋‰ด๋ฅผ ์ƒ์œ„๋ฉ”๋‰ด ๊ฐ์ฒด์™€ ํ•˜์œ„ ๋ฉ”๋‰ด ๊ฐ์ฒด๋กœ ์บก์Šํ™” ํ•˜๊ณ  ๊ฐ์ฒด๋ผ๋ฆฌ ์ƒํ˜ธ์ž‘์šฉํ•˜๋„๋ก ์ˆ˜์ •ํ•œ๋‹ค. ํด๋”์™€ ํŒŒ์ผ์˜ ๊ตฌ์กฐ์ฒ˜๋Ÿผ ๊ณ„์ธต์ ์ธ ํŠธ๋ฆฌ๊ตฌ์กฐ์˜ ํ˜•์‹์„ ์ทจํ•œ๋‹ค.

img.png

์šฐ์„  Menu์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•ด MenuGroup๊ณผ MenuItem์„ ๊ณตํ†ต์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋งŒ๋“ ๋‹ค. MenuGroup ์€ ๋ฐ˜๋ณต์ ์œผ๋กœ Menu๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‹ค. ์ฆ‰, MenuGroup ๋˜๋Š” MenuItem ์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‹ค.(add() ๋กœ ๋ฐฐ์—ด์— ์ถ”๊ฐ€)

๋ฐ์ดํ„ฐ๋ฅผ ์ด๋Ÿฐ์‹์œผ๋กœ ์กฐ์งํ™”ํ•˜๋‹ค ๋ณด๋ฉด ๋ณตํ•ฉ๊ฐ์ฒด(MenuGroup)๋ฅผ ๋”ฐ๋ผ์„œ ๊ฐ€์ง€๊ฐ€ ์—ฐ๊ฒฐ๋˜๋‹ค๊ฐ€ ๋งˆ์ง€๋ง‰์—๋Š” ์žŽ(MenuItem)์œผ๋กœ ๋๋‚˜๋Š” ํŠธ๋ฆฌ๊ตฌ์กฐ๊ฐ€ ๋งŒ๋“ค์–ด์ง„๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class MenuGroup implements Menu {

  String title;
  Menu[] menus = new Menu[10];
  int menuSize;

  public MenuGroup(String title) {
    this.title = title;
  }

  public void add(Menu menu) {
    // menus ๋ฐฐ์—ด์— ์„œ๋ธŒ๋ฉ”๋‰ด๋ฅผ ๋„ฃ๋Š”๋‹ค
  }

  public void remove(Menu menu) {
    // menus ๋ฐฐ์—ด์—์„œ ์„œ๋ธŒ๋ฉ”๋‰ด ์‚ญ์ œ
  }
  
  @Override
  public void execute(Prompt prompt) {
    this.printMenu();
    // ๋ฉ”๋‰ด ๋ฒˆํ˜ธ ์ž…๋ ฅ ๋ฐ ๋ฉ”๋‰ด ์ถœ๋ ฅ
    // menus ๋ฐฐ์—ด์— ์žˆ๋Š” ์„œ๋ธŒ๋ฉ”๋‰ด ์‹คํ–‰(execute)
    
  }
}

๊ธฐ์กด ์†Œ์Šค์—์„œ๋Š” add(),remove() ์™€ ๊ฐ™์ด ๋ฉ”๋‰ด๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  ์‚ญ์ œํ•˜๋Š” ๊ธฐ๋Šฅ์ด ๊ฐ๊ฐ์˜ ๋ฉ”๋‰ด์— ์กด์žฌํ–ˆ๋‹ค. ์ด์ œ ์ƒˆ๋กœ์šด ๋ฉ”๋‰ด๋ฅผ ๋งŒ๋“œ๋Š” ์ž‘์—…์€ MenuGroup์—์„œ ํ•œ๋‹ค. MenuGroup์—์„œ ์„œ๋ธŒํด๋ž˜์Šค ์š”์†Œ๋“ค์„ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ menus ๋ฐฐ์—ด์ด ์žˆ๊ณ  ํ•ด๋‹น ๋ฐฐ์—ด์— ์ถ”๊ฐ€/์‚ญ์ œ๋Š” add(), remove()๋ฅผ ํ†ตํ•ด์„œ ํ•œ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class MenuItem implements Menu {

  String title;
  MenuHandler menuHandler;

  public MenuItem(String title) {
    this.title = title;
  }

  public MenuItem(String title, MenuHandler menuHandler) {
    this(title);
    this.menuHandler = menuHandler;
  }

  @Override
  public void execute(Prompt prompt) {
    if (this.menuHandler != null) {
      this.menuHandler.action();
    }
  }

  @Override
  public String getTitle() {
    return this.title;
  }

์ปดํฌ์ง€ํŠธ ํŒจํ„ด์—์„œ leaf ์— ํ•ด๋‹นํ•˜๋Š” ๋ถ€๋ถ„์ด๋‹ค. leaf ๋ถ€๋ถ„์€ CRUD ์ž‘์—…์— ๋Œ€ํ•œ MenuHandler ๋ฅผ ์ฃผ์ž…๋ฐ›์•„ ์‚ฌ์šฉํ•œ๋‹ค. ์ด๋Š” ๊ธฐ์กด์— ๋ฉ”๋‰ด ๊ฐ์ฒด์— ์„ž์—ฌ์žˆ๋˜ ๋ฉ”๋‰ด ์ถœ๋ ฅ๊ณผ CRUD ๊ธฐ๋Šฅ ๋ถ€๋ถ„์„ ๋ถ„๋ฆฌ์‹œํ‚ค๊ธฐ ์œ„ํ•จ์ด๋‹ค.

Client

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class Client {
  public static void main(String[] args) {
    ...

    Prompt prompt = new Prompt(System.in);
    //    new MainMenu(prompt).execute(); 
    BoardRepository boardRepository = new BoardRepository();

    MenuGroup mainMenu = new MenuGroup("๋ฉ”์ธ");
    MenuGroup assignmentMenu = new MenuGroup("๊ณผ์ œ");
    MenuGroup boardMenu = new MenuGroup("๊ฒŒ์‹œ๊ธ€");
    MenuGroup memberMenu = new MenuGroup("ํšŒ์›");
    MenuGroup greetingMenu = new MenuGroup("๊ฐ€์ž…์ธ์‚ฌ");
    MenuGroup helpMenu = new MenuGroup("๋„์›€๋ง");

    mainMenu.add(assignmentMenu);
    assignmentMenu.add(new MenuItem("๋“ฑ๋ก"));
    assignmentMenu.add(new MenuItem("์กฐํšŒ"));
    assignmentMenu.add(new MenuItem("๋ณ€๊ฒฝ"));
    assignmentMenu.add(new MenuItem("์‚ญ์ œ"));
    assignmentMenu.add(new MenuItem("๋ชฉ๋ก"));

    mainMenu.add(boardMenu);
    boardMenu.add(new MenuItem("๋“ฑ๋ก", new BoardAddHandler(boardRepository, prompt)));
    boardMenu.add(new MenuItem("์กฐํšŒ", new BoardViewHandler()));
    boardMenu.add(new MenuItem("๋ณ€๊ฒฝ", new BoardModifyHandler()));
    boardMenu.add(new MenuItem("์‚ญ์ œ", new BoardDeleteHandler()));
    boardMenu.add(new MenuItem("๋ชฉ๋ก", new BoardListHandler(boardRepository)));
  }
}

์ปดํฌ์ง€ํŠธ ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ์‚ฌ์šฉ์ž๊ฐ€ ๋‹จ์ผ ๊ฐ์ฒด์™€ ๋ณตํ•ฉ ๊ฐ์ฒด ๋ชจ๋‘ ๋™์ผํ•˜๊ฒŒ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๋‹ค. ๊ธฐ์กด์— new MainMenu(prompt).execute() ๋กœ ๊ฐ ๋ฉ”๋‰ด๋“ค์„ ํ˜ธ์ถœํ–ˆ๋‹ค๋ฉด ์ด์ œ๋Š” ๋ฉ”๋‰ด์˜ ์ข…์†๊ด€๊ณ„๊ฐ€ ์ฝ”๋“œ์ƒ์— ํ™•์‹คํžˆ ํ‘œํ˜„๋˜๊ณ , ์ถ”๊ฐ€/์‚ญ์ œ๋ฅผ ๊ฐ„ํŽธํžˆ ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ „์ฒด ์†Œ์Šค

๋ฐฉ๋ฌธํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค! ๋Œ“๊ธ€,์ง€์ ,ํ”ผ๋“œ๋ฐฑ ์–ธ์ œ๋‚˜ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค๐Ÿ˜Š

๋Œ“๊ธ€๋‚จ๊ธฐ๊ธฐ