Как создавать разные экземпляры с помощью одноэлементного шаблона?

#c #oop #design-patterns #singleton

#c #ооп #шаблоны проектирования #singleton

Вопрос:

Мне нужно создать простое приложение, например корзину покупок.

main.cpp

 int main()
{
    Cart cart;
    // add items
    cart.addItem("Shirt", ItemType:Clothing);
    cart.addItem("Xbox", ItemType::Entertainment);
    cart.addItem("Bowl", ItemType::Cooking);
    // print item
    cart.printItems();
    Item::destroy();
}
  

Item.h

 enum ItemType
{
    Cooking,
    Clothing,
    Entertainment
};

class Item
{
private: 
    Item(const std::stringamp; name, const ItemTypeamp; itemType);
    static Item* m_instance;
    std::string m_name;
    ItemType m_itemType;

public:
    static Item *getInstance(const std::stringamp; name, const ItemTypeamp; itemType);    
    static void destroy();
    const std::stringamp; getName() const;
    const ItemTypeamp; getItemType() const;
    void print() const;
};
  

Item.cpp

 Item* Item::m_instance = nullptr;
Item::Item(const std::stringamp; name, const ItemTypeamp; itemType)
{
    m_name = name;
    m_itemType = itemType;
}

Item* Item::getInstance(const std::stringamp; name, const ItemTypeamp; itemType)
{
    if (!m_instance) {
        m_instance = new Item(name, itemType);
    }
    return m_instance;
}

void Item::destroy()
{
    delete m_instance;
    m_instance = nullptr;
}

void Item::print() const
{
    std::cout << "Item name: " << m_name << std::endl;
}
  

Cart.h

 class Cart
{
public:
    Cart();
    ~Cart();

    void addItem(const std::stringamp; name, const ItemTypeamp; itemType);
    void printItems();

private:
    std::vector<Item*> m_itemList = {};
};
  

Cart.cpp

 void Cart::addItem(const std::stringamp; name, const ItemTypeamp; itemType)
{
    Item *newItem = Item::getInstance(name, itemType);
    m_itemList.push_back(newItem);  
}

void Cart::printItems()
{
    std::cout << "Items" << std::endl;
    for (int i = 0; i < m_itemList.size(); i  )
    {
        m_itemList[i]->print();
    }
    std::cout << std::endl;
}
  

Когда я запускаю этот код, результат

Item name: Shirt

Item name: Shirt

Item name: Shirt

что мне нужно, так это

Item name: Shirt

Item name: Xbox

Item name: Bowl

Я изучаю шаблон проектирования. Я знаю, что цель этого — создать только один экземпляр. В этом примере я должен использовать одноэлементный шаблон. Но я не знаю, где я ошибаюсь, поэтому я получаю этот результат. Не могли бы вы сказать мне, где я должен исправить свой код? Большое спасибо!

Комментарии:

1. Ни один класс, который вы показали здесь, не кажется хорошим кандидатом для singleton, и особенно нет Item .

2. Разве несколько экземпляров и одноэлемент не противоречат друг другу? Вы имеете в виду что-то вроде уникального экземпляра в наборе или карте?

3. Что касается шаблонов проектирования , я полагаю, вам нужна фабрика , которая, в свою очередь, может быть реализована как одноэлементный или фабричный метод . На самом деле конкретная проблема заключается в том static Item* m_instance; , что Item одновременно допускается только один экземпляр, когда вам нужно их много.

4. @gnase вы добавляете несколько «элементов» в корзину, поэтому просто не имеет смысла, чтобы в памяти был только 1 Item объект, вам нужно несколько Item объектов. Поэтому использование одноэлементного дизайна для Item не имеет смысла. Item *newItem = Item::getInstance(name, itemType); должно быть Item *newItem = new Item(name, itemType); вместо этого, если вы не избавитесь от Item::m_instance него полностью и не измените Item::getInstance() его на return new Item(name, itemType) каждый раз, когда он вызывается.

5. @gnase Абстрактный класс с private конструктором был бы немного бесполезным, не так ли? Но хорошо, getInstance() если вы все еще можете раздавать указатели, созданные с new помощью, просто не храните их в static Item* m_instance; .