#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>
#include <memory>
class TreeType {
public:
TreeType(const std::string& name, const std::string& color, const std::string& texture)
: name_(name), color_(color), texture_(texture) {}
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_;
};
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(); }
private:
std::unordered_map<std::string, std::shared_ptr<TreeType>> treeTypes_;
};
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;
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";
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);
}
}
}
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;
}