#pragma once

#include <string>
#include <functional>
#include <map>

class Object {
 public:
    virtual std::string ToString() const = 0;
    virtual ~Object() {}
};

class Apple : public Object {
 public:
    explicit Apple(const std::string& class_id) : class_id_(class_id) {}

    std::string ToString() const override {
        return class_id_;
    }

 private:
    const std::string class_id_;
};

class List : public Object {
 public:
    explicit List(const std::string& class_id) : class_id_(class_id) {}

    std::string ToString() const override {
        return class_id_;
    }

 private:
    const std::string class_id_;
};

class YetAnotherIdentifier : public Object {
 public:
    explicit YetAnotherIdentifier(const std::string& class_id) :
    class_id_(class_id) {}

    std::string ToString() const override {
        return class_id_;
    }

 private:
    const std::string class_id_;
};

class Factory {
 public:
    Object* Create(const std::string& class_id) {
        if (class_id == "apple!") {
            return new Apple(class_id);
        } else if (class_id == "list") {
            return new List(class_id);
        } else if (class_id == "yet another identifier") {
            return new YetAnotherIdentifier(class_id);
        } else {
            return create_another_functions[class_id]();
        }
    }

    void Register(const std::string& class_id, Object*(*instance_creator)()) {
        create_another_functions[class_id] = instance_creator;
    }

 private:
    std::map<std::string, std::function<Object*()>> create_another_functions;
};