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

// Flyweight: Stores shareable intrinsic state (tree name, color, texture)
class TreeType {
public:
    TreeType(const std::string& name, const std::string& color, const std::string& texture)
        : name_(name), color_(color), texture_(texture) {}

    // Needs extrinsic state (coordinates, size) as parameters when drawing
    void draw(int x, int y, int size) const {
        std::cout << "Drawing " << name_ << " tree [" 
                  << color_ << ", " << texture_ << "] at (" 
                  << x << ", " << y << "), size " << size 
                  << "  (TreeType addr: " << this << ")\n";
    }

    const std::string& getName() const { return name_; }

private:
    std::string name_;
    std::string color_;
    std::string texture_;   // Shareable data like texture
};

// Flyweight Factory: Creates and shares TreeType objects
class TreeFactory {
public:
    std::shared_ptr<TreeType> getTreeType(const std::string& name,
                                          const std::string& color,
                                          const std::string& texture) {
        auto it = treeTypes_.find(name);
        if (it != treeTypes_.end()) {
            std::cout << "  [Flyweight] Reusing existing TreeType: " << name << "\n";
            return it->second;
        }
        std::cout << "  [Flyweight] Creating new TreeType: " << name << "\n";
        auto treeType = std::make_shared<TreeType>(name, color, texture);
        treeTypes_[name] = treeType;
        return treeType;
    }

    size_t getCount() const { return treeTypes_.size(); }  // Number of shared objects

private:
    std::unordered_map<std::string, std::shared_ptr<TreeType>> treeTypes_;
};

// 树:包含外在状态(位置、大小)和一个指向共享 TreeType 的指针
class Tree {
public:
    Tree(int x, int y, int size, std::shared_ptr<TreeType> type)
        : x_(x), y_(y), size_(size), type_(std::move(type)) {}

    void draw() const {
        type_->draw(x_, y_, size_);
    }

private:
    int x_, y_, size_;                     // 外在状态(每棵树不同)
    std::shared_ptr<TreeType> type_;       // 内在状态(共享)
};

// 森林:管理所有树木
class Forest {
public:
    void plantTree(int x, int y, int size, std::shared_ptr<TreeType> type) {
        trees_.emplace_back(x, y, size, std::move(type));
    }

    void draw() const {
        for (const auto& tree : trees_) {
            tree.draw();
        }
    }

private:
    std::vector<Tree> trees_;
};

// ---------- 主程序 ----------
int main() {
    TreeFactory factory;
    Forest forest;

    // 获取两种享元类型(实际只会创建两个 TreeType 对象)
    std::cout << "=== Creating tree types ===\n";
    auto oak  = factory.getTreeType("Oak",  "Green",      "Rough");
    auto pine = factory.getTreeType("Pine", "Dark Green", "Smooth");

    // 反复获取同一种类型,工厂会直接返回已缓存的对象
    auto oak2 = factory.getTreeType("Oak", "Green", "Rough");
    std::cout << "oak  address: " << oak.get() 
              << ", oak2 address: " << oak2.get() 
              << "  (same object: " << (oak == oak2 ? "yes" : "no") << ")\n\n";

    // 种植大量树(它们共享两种 TreeType)
    std::cout << "=== Planting forest (50 trees) ===\n";
    for (int i = 0; i < 5; ++i) {
        for (int j = 0; j < 10; ++j) {
            if ((i + j) % 2 == 0) {
                forest.plantTree(i * 10, j * 10, 5 + i, oak);
            } else {
                forest.plantTree(i * 10, j * 10, 4 + j, pine);
            }
        }
    }

    // 绘制所有树,观察输出的 TreeType 地址是否相同
    std::cout << "\n=== Drawing forest ===\n";
    forest.draw();

    // 统计享元数量,说明节省的内存
    std::cout << "\n=== Statistics ===\n";
    std::cout << "Total trees: " << 5 * 10 << "\n";
    std::cout << "Distinct TreeType objects created: " << factory.getCount() << "\n";
    std::cout << "Without Flyweight, we would have created many more TreeType objects.\n";

    return 0;
}

results matching ""

    No results matching ""