๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๋””์ž์ธํŒจํ„ด

[๋””์ž์ธํŒจํ„ด] ์ปดํฌ์ง€ํŠธ(Composite) ํŒจํ„ด

by ์„œ์•„๋ž‘๐Ÿ˜ 2024. 8. 25.

 

 

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

  • *์ปดํฌ์ง€ํŠธ ํŒจํ„ด(Composite Pattern)**์€ ๊ตฌ์กฐ์  ๋””์ž์ธ ํŒจํ„ด ์ค‘ ํ•˜๋‚˜๋กœ, ๊ฐ์ฒด๋ฅผ ํŠธ๋ฆฌ ๊ตฌ์กฐ๋กœ ๊ตฌ์„ฑํ•˜์—ฌ ๋ถ€๋ถ„-์ „์ฒด ๊ณ„์ธต์„ ํ‘œํ˜„ํ•  ๋•Œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ์ด ํŒจํ„ด์€ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋‹จ์ผ ๊ฐ์ฒด์™€ ๋ณตํ•ฉ ๊ฐ์ฒด๋ฅผ ๋™์ผํ•œ ๋ฐฉ์‹์œผ๋กœ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ค๋‹ˆ๋‹ค. ์ฆ‰, ๊ฐœ๋ณ„ ๊ฐ์ฒด(Leaf)์™€ ๋ณตํ•ฉ ๊ฐ์ฒด(Composite)๋ฅผ ๋™์ผํ•œ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

1. ์ปดํฌ์ง€ํŠธ ํŒจํ„ด์˜ ๊ธฐ๋ณธ ๊ฐœ๋…

  • ๊ตฌ์„ฑ ์š”์†Œ:
    1. Component: ๊ฐ์ฒด๋“ค ๊ฐ„์˜ ๊ณตํ†ต ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—๋Š” Leaf์™€ Composite์—์„œ ๊ณตํ†ต์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๋ฉ”์„œ๋“œ๊ฐ€ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.
    2. Leaf: ํŠธ๋ฆฌ์˜ ๋ง๋‹จ ๋…ธ๋“œ๋ฅผ ํ‘œํ˜„ํ•˜๋ฉฐ, ๋” ์ด์ƒ ์ž์‹์„ ๊ฐ€์ง€์ง€ ์•Š๋Š” ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค. Component ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.
    3. Composite: ์ž์‹ ๋…ธ๋“œ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋Š” ๋ณตํ•ฉ ๊ฐ์ฒด๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. Component ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๋ฉฐ, ์ž์‹ ๋…ธ๋“œ๋“ค์„ ๊ด€๋ฆฌํ•˜๊ณ  ์ด๋“ค์— ๋Œ€ํ•œ ์—ฐ์‚ฐ์„ ์œ„์ž„ํ•ฉ๋‹ˆ๋‹ค.

 

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


2. ์ปดํฌ์ง€ํŠธ ํŒจํ„ด ์˜ˆ์ œ

์•„๋ž˜ ์˜ˆ์ œ์—์„œ๋Š” ํŒŒ์ผ ์‹œ์Šคํ…œ์„ ๋ชจ๋ธ๋งํ•˜๋Š” ๊ตฌ์กฐ๋ฅผ ํ†ตํ•ด ์ปดํฌ์ง€ํŠธ ํŒจํ„ด์„ ๊ตฌํ˜„ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด ํŒŒ์ผ ์‹œ์Šคํ…œ์—์„œ๋Š” ํŒŒ์ผ๊ณผ ๋””๋ ‰ํ„ฐ๋ฆฌ๊ฐ€ ์žˆ์œผ๋ฉฐ, ๋””๋ ‰ํ„ฐ๋ฆฌ๋Š” ๋‹ค๋ฅธ ํŒŒ์ผ์ด๋‚˜ ๋””๋ ‰ํ„ฐ๋ฆฌ๋ฅผ ํฌํ•จํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

#include <iostream>
#include <vector>
#include <memory>
#include <string>

// Component
class FileSystemComponent {
public:
    virtual void showDetails(int indent = 0) const = 0;
    virtual ~FileSystemComponent() = default;
};

// Leaf
class File : public FileSystemComponent {
private:
    std::string name;
public:
    File(const std::string& name) : name(name) {}

    void showDetails(int indent = 0) const override {
        std::cout << std::string(indent, '-') << name << std::endl;
    }
};

// Composite
class Directory : public FileSystemComponent {
private:
    std::string name;
    std::vector<std::unique_ptr<FileSystemComponent>> children;
public:
    Directory(const std::string& name) : name(name) {}

    void add(std::unique_ptr<FileSystemComponent> component) {
        children.push_back(std::move(component));
    }

    void showDetails(int indent = 0) const override {
        std::cout << std::string(indent, '-') << name << std::endl;
        for (const auto& child : children) {
            child->showDetails(indent + 2);
        }
    }
};

int main() {
    // ๋ฃจํŠธ ๋””๋ ‰ํ„ฐ๋ฆฌ ์ƒ์„ฑ
    auto root = std::make_unique<Directory>("root");

    // ๋ฃจํŠธ ๋””๋ ‰ํ„ฐ๋ฆฌ์— ํŒŒ์ผ ์ถ”๊ฐ€
    root->add(std::make_unique<File>("file1.txt"));
    root->add(std::make_unique<File>("file2.txt"));

    // ์„œ๋ธŒ ๋””๋ ‰ํ„ฐ๋ฆฌ ์ƒ์„ฑ ๋ฐ ํŒŒ์ผ ์ถ”๊ฐ€
    auto subDir = std::make_unique<Directory>("subdir");
    subDir->add(std::make_unique<File>("file3.txt"));
    subDir->add(std::make_unique<File>("file4.txt"));

    // ์„œ๋ธŒ ๋””๋ ‰ํ„ฐ๋ฆฌ๋ฅผ ๋ฃจํŠธ ๋””๋ ‰ํ„ฐ๋ฆฌ์— ์ถ”๊ฐ€
    root->add(std::move(subDir));

    // ์ „์ฒด ํŒŒ์ผ ์‹œ์Šคํ…œ ๊ตฌ์กฐ ์ถœ๋ ฅ
    root->showDetails();

    return 0;
}

3. ์ฝ”๋“œ ์„ค๋ช…

  1. Component: FileSystemComponent๋Š” ํŒŒ์ผ๊ณผ ๋””๋ ‰ํ„ฐ๋ฆฌ ๋ชจ๋‘๊ฐ€ ๊ตฌํ˜„ํ•ด์•ผ ํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋กœ, ์—ฌ๊ธฐ์„œ๋Š” showDetails() ๋ฉ”์„œ๋“œ๋ฅผ ์ •์˜ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ฉ”์„œ๋“œ๋Š” ๊ฐ์ฒด์˜ ์„ธ๋ถ€ ์ •๋ณด๋ฅผ ์ถœ๋ ฅํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.
  2. Leaf: File ํด๋ž˜์Šค๋Š” ๊ฐœ๋ณ„ ํŒŒ์ผ์„ ๋‚˜ํƒ€๋‚ด๋ฉฐ, showDetails() ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜์—ฌ ํŒŒ์ผ ์ด๋ฆ„์„ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค.
  3. Composite: Directory ํด๋ž˜์Šค๋Š” ๋””๋ ‰ํ„ฐ๋ฆฌ๋ฅผ ๋‚˜ํƒ€๋‚ด๋ฉฐ, ๋‹ค๋ฅธ FileSystemComponent ๊ฐ์ฒด๋“ค์„ ์ž์‹์œผ๋กœ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. add() ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ์ž์‹ ๊ฐ์ฒด๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉฐ, showDetails() ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ์ž์‹๋“ค์˜ ์„ธ๋ถ€ ์ •๋ณด๋ฅผ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค.
  4. Client: main() ํ•จ์ˆ˜๋Š” ํŒŒ์ผ ์‹œ์Šคํ…œ์˜ ํŠธ๋ฆฌ ๊ตฌ์กฐ๋ฅผ ๊ตฌ์„ฑํ•˜๊ณ , ์ „์ฒด ๊ตฌ์กฐ๋ฅผ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค.

4. ์‹คํ–‰ ๊ฒฐ๊ณผ

์œ„์˜ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ถœ๋ ฅ์ด ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค:

root
--file1.txt
--file2.txt
--subdir
----file3.txt
----file4.txt

์„ค๋ช…:

  • root ๋””๋ ‰ํ„ฐ๋ฆฌ ์•„๋ž˜์— file1.txt์™€ file2.txt ํŒŒ์ผ์ด ์žˆ๊ณ , subdir๋ผ๋Š” ์„œ๋ธŒ ๋””๋ ‰ํ„ฐ๋ฆฌ๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.
  • subdir ์•„๋ž˜์—๋Š” file3.txt์™€ file4.txt ํŒŒ์ผ์ด ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๊ฐ ๋””๋ ‰ํ„ฐ๋ฆฌ์™€ ํŒŒ์ผ์€ ๊ณ„์ธต์ ์œผ๋กœ ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค.

์ด ์˜ˆ์ œ๋Š” ์ปดํฌ์ง€ํŠธ ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜์—ฌ ํŠธ๋ฆฌ ๊ตฌ์กฐ๋ฅผ ๊ฐ€์ง„ ๊ฐ์ฒด๋ฅผ ๋™์ผํ•œ ๋ฐฉ์‹์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ์—์„œ๋Š” ๊ฐœ๋ณ„ ๊ฐ์ฒด(ํŒŒ์ผ)์™€ ๋ณตํ•ฉ ๊ฐ์ฒด(๋””๋ ‰ํ„ฐ๋ฆฌ)๋ฅผ ๊ตฌ๋ถ„ํ•  ํ•„์š” ์—†์ด showDetails() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๊ตฌ์กฐ๋ฅผ ์ถœ๋ ฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋Œ“๊ธ€