У меня есть ситуация, когда классы A, B и C являются производными от X для создания составного шаблона.
А, В и С очень похожи, но у них разные внутренние атрибуты. Мой вопрос заключается в том, как мне получить доступ к их атрибутам и изменить их после того, как они будут добавлены в композит без приведения их к типу?
В моем реальном примере отношение часть-целое имеет смысл, и все элементы поддерживают основную операцию, поэтому мне это и нужно. При этом отдельные классы в композите имеют разные атрибуты и требуют специальных операций.
Есть ли способ отделить эти специальные свойства и связанные с ними функции от составного класса, но привязать их к ним?
Для наглядности предположим, что у нас есть композит merchandise
(базовый класс композита), у которого есть цена. Теперь магазин — это товар, в нем отдел — это товар, в котором фактический товар называется pot
это товар, в нем может быть набор горшков с комбинированными горшками, который также является товаром, и так далее.
class Merchandise
{
public:
virtual void add(Merchandise* item) = 0;
virtual Merchandise* getMerchandise() = 0;
virtual void show() = 0;
// assume we have the following key operations here but I am not implementing them to keep this eitemample short
//virtual setPrice(float price) = 0;
//virtual float getPrice() = 0;
};
class Store : public Merchandise
{
vector< Merchandise*> deparments;
std::string storeName = "";
public:
Store(std::string store_name) : storeName(store_name) {}
virtual void add(Merchandise* item)
{
deparments.push_back(item);
}
virtual Merchandise* getMerchandise()
{
if (deparments.size() > 0)
return deparments[0];
return 0;
}
virtual void show()
{
cout << "I am Store " << storeName << " and have following " << deparments.size() << " departments" << endl;
for (unsigned int i = 0; i < deparments.size(); i++)
{
deparments[i]->show();
}
}
};
class Department : public Merchandise
{
std::string depName;
vector<Merchandise*> items;
public:
Department(std::string dep_name) : depName(dep_name) {}
virtual void add(Merchandise* item)
{
items.push_back(item);
}
virtual Merchandise* getMerchandise()
{
if (items.size() > 0)
return items[0];
return 0;
}
virtual void show()
{
cout << "I am department " << depName << " and have following " << items.size() << " items" << endl;
for (unsigned int i = 0; i < items.size(); i++)
{
items[i]->show();
}
}
};
class Shirt : public Merchandise
{
std::string shirtName;
public:
Shirt(std::string shirt_name) : shirtName(shirt_name) {}
virtual void add(Merchandise* item) {}
virtual Merchandise* getMerchandise() { return 0; }
virtual void show()
{
cout << "I am shirt " << shirtName << endl;
};
};
class Pot : public Merchandise
{
std::string potName;
public:
Pot(std::string pot_name) : potName(pot_name) {}
virtual void add(Merchandise* item) { }
virtual Merchandise* getMerchandise() { return 0; }
virtual void show()
{
cout << "I am pot " << potName << endl;
};
int num = 0;
};
class CookSet : public Merchandise
{
std::string cooksetName;
vector<Merchandise*> pots;
public:
CookSet(std::string cookset_name) : cooksetName(cookset_name) {}
vector<Merchandise*> listOfPots;
virtual void add(Merchandise* item) { pots.push_back(item); }
virtual Merchandise* getMerchandise() { return 0; }
virtual void show()
{
cout << "I am cookset " << cooksetName << " and have following " << pots.size() << " items" << endl;
for (unsigned int i = 0; i < pots.size(); i++)
{
pots[i]->show();
}
};
int num = 0;
};
int main()
{
// create a store
Store * store = new Store( "BigMart");
// create home department and its items
Department * mens = new Department( "Mens");
mens->add(new Shirt("Columbia") );
mens->add(new Shirt("Wrangler") );
// likewise a new composite can be dress class which is made of a shirt and pants.
Department * kitchen = new Department("Kitchen");
// create kitchen department and its items
kitchen->add(new Pot("Avalon"));
CookSet * cookset = new CookSet("Faberware");
cookset->add(new Pot("Small Pot"));
cookset->add(new Pot("Big pot"));
kitchen->add(cookset);
store->add( mens );
store->add(kitchen);
store->show();
// so far so good but the real fun begins after this.
// Firt question is, how do we even access the deep down composite objects in the tree?
// this wil not really make sense!
Merchandise* item = store->getMerchandise()->getMerchandise();
// Which leads me to want to add specific method to CStore object like the following to retrieve each department
// but then does this break composite pattern? If not, how can I accomodate these methods only to CStore class?
//store->getMensDept();
//store->getsKitchenDept();
// Likewise a shirt class will store different attributes of a shirt like collar size, arm length etc, color.
// how to retrieve that?
// Other operations is, say if item is cookset, set it on 20% sale.
// Another if its a shirt and color is orange, set it on 25% sale (a shirt has a color property but pot doesn't).
// how to even dispaly particular attributes of that item in a structure?
// item->getAttributes();
return 0;
}
Проблема с этой строкой, как только я заполнил композит.
Merchandise* item = store->getMerchandise()->getMerchandise();
Во-первых, из моей структуры кода я знаю, что это должен быть определенный тип, но, как рекомендуется, мы не должны приводить это к типу!? Но я хочу изменить его уникальные свойства, так как мне этого добиться?
Предположим, что в этом магазине также продаются рубашки, и я хочу изменить его свойства (или даже просто показать их!), он сильно отличается от горшка.
Какой подход здесь был бы лучшим? Я думаю, что если мы сможем каким-то образом разделить уникальные свойства каждого композита на разные классы, таким образом композит тоже останется компактнее, но не уверен, как этого добиться.
Я предполагаю, что в реальной жизни нет идеального композита, и составные классы будут иметь некоторые различия. Как мы справляемся с этим?
Обновить
Обратите внимание, что я использовал пример merchandise
для объяснения проблемы. В моем реальном примере все A
, B
, C
являются производными от X
. A
содержит несколько элементов B
, которые содержат несколько элементов C
. Когда операция выполняется над A
, ее необходимо выполнять над ее составными частями, поэтому я использую композит. Но тогда у каждого композита есть разные атрибуты. Композит не подходит для этого?
store->getMerchandise()->getMerchandise();
здесь не имеет особого смысла, но в то же время очень неясно, как вы собираетесь использовать эту древовидную структуруMerchansdise
. В интерфейсе нет открытого метода, кромеshow
, и вы также не приводите пример того, как вы собираетесь его использовать. Я думаю, что некоторые примеры использования от вас прояснят ситуацию и дадут вам более подходящие ответы. - person super   schedule 19.08.2018