#pragma once
//˵����һ��ģ�幤���࣬�ȵ���ע�������ע�ᣬע�������ͨ�������ַ�������ָ������
//ע��,example(static ProductRegistrar<DeviceBase, RingLight> device_ringlight("ringlight");)

// ���࣬��Ʒע��ģ��ӿ���
// ģ����� ProductType_t ��ʾ�����Dz�Ʒ������
template <class ProductType_t>
class IProductRegistrar
{
public:
    // ��ȡ��Ʒ�������ӿ�
    virtual ProductType_t* CreateProduct() = 0;

protected:
    // ��ֹ�ⲿ������鹹, �����"�ڲ�"�������������Ե���
    IProductRegistrar() {}
    virtual ~IProductRegistrar() {}

private:
    // ��ֹ�ⲿ�����͸�ֵ����
    IProductRegistrar(const IProductRegistrar&);
    const IProductRegistrar& operator=(const IProductRegistrar&);
};

// ����ģ���࣬���ڻ�ȡ��ע���Ʒ����
// ģ����� ProductType_t ��ʾ�����Dz�Ʒ������
template <class ProductType_t>
class ProductFactory
{
public:
    // ��ȡ����������������ʵ����Ψһ��
    static ProductFactory<ProductType_t>& Instance()
    {
        static ProductFactory<ProductType_t> instance;
        return instance;
    }

    // ��Ʒע��
    void RegisterProduct(IProductRegistrar<ProductType_t>* registrar, string name)
    {
        m_ProductRegistry[name] = registrar;
    }

    // ��������name����ȡ��Ӧ����IJ�Ʒ����
    ProductType_t* GetProduct(string name)
    {
        // ��map�ҵ��Ѿ�ע����IJ�Ʒ�������ز�Ʒ����
        if (m_ProductRegistry.find(name) != m_ProductRegistry.end())
        {
            return m_ProductRegistry[name]->CreateProduct();
        }

        // δע��IJ�Ʒ���򱨴�δ�ҵ�
        //std::cout << "No product found for " << name << std::endl;

        return NULL;
    }

private:
    // ��ֹ�ⲿ������鹹
    ProductFactory() {}
    ~ProductFactory() {}

    // ��ֹ�ⲿ�����͸�ֵ����
    ProductFactory(const ProductFactory&);
    const ProductFactory& operator=(const ProductFactory&);

    // ����ע����IJ�Ʒ��key:��Ʒ���� , value:��Ʒ����
    map<string, IProductRegistrar<ProductType_t>*> m_ProductRegistry;
};

// ��Ʒע��ģ���࣬���ڴ��������Ʒ�ʹӹ�����ע���Ʒ
// ģ����� ProductType_t ��ʾ�����Dz�Ʒ�����ࣨ���ࣩ��ProductImpl_t ��ʾ�����Ǿ����Ʒ����Ʒ��������ࣩ
template <class ProductType_t, class ProductImpl_t>
class ProductRegistrar : public IProductRegistrar<ProductType_t>
{
public:
    // ���캯��������ע���Ʒ��������ֻ����ʾ����
    explicit ProductRegistrar(string name)
    {
        // ͨ�����������Ѳ�Ʒע�ᵽ����
        ProductFactory<ProductType_t>::Instance().RegisterProduct(this, name);
    }

    // ���������Ʒ����ָ��
    ProductType_t* CreateProduct()
    {
        return new ProductImpl_t();
    }
};