У меня вопрос о интерфейсе, скажем:
class IAnimal
{ ...
Public:
virtual void makeSound() = 0;
};
class Cat : public IAnimal
{ ...
void makeSound() { std::cout << "purr" << std::endl; }
};
class Dog : public IAnimal
{ ...
void makeSound() { std::cout << "bark" << std::endl; }
};
class AnimalFactory
{
std::shared_ptr<IAnimal> createAnimal(animalType type)
{
std::shared_ptr<IAnimal> animal;
switch(type)
{ case animal_type::cat: animal = std::shared_ptr<Cat>(); break;
case animal_type::dog: animal = std::shared_ptr<Dog>(); break;
… }
return animal;
}
};
class App
{ ...
std::shared_ptr<IAnimal> _animal;
AnimalFactory::animal_type type;
void haveCat()
{ ...
type = AnimalFactory::animal_type::cat;
_animal = AnimalFactory.createAnimal(type);
_animal->makeSound();
...
}
};
теперь мне нужна эта кошка, чтобы поймать мышь void catchMouse() {std :: cout << "поймать мышей"; } }
void haveCat()
{ ...
type = AnimalFactory::animal_type::cat;
_animal = AnimalFactory.createAnimal(type);
_animal->makeSound();
// catchMouse();
...
}
Существует несколько возможных решений, но они не выглядят хорошо.
добавьте общедоступный метод catchMouse() в Cat и добавьте _animal в метод Cat в hasCat().
{
_cat = std::dynamic_pointer_cast<Cat>(AnimalFactory.createAnimal(type));
_cat->makeSound();
_cat->catchMouse();
}
но есть динамичный бросок, а не хороший, не так ли?
пусть Cat реализует интерфейс IAnimal и еще один интерфейс о мыши, но AnimalFactory возвращает только std :: shared_ptr, и мы не можем вызвать catchMouse в IAnimal.
То, что я говорю здесь, - это публичный метод в одном подклассе, но другого подкласса нет, как его проектировать, если мы используем фабрику. Пожалуйста, не отвечайте, позвольте собаке поймать кролика, затем добавьте метод catch() в IAnimal, поэтому кошка может поймать мышку, собака может поймать кролика.
Какое хорошее решение для этого вопроса? Благодарю.
Я полагаю, способ справиться с этой проблемой - это вариация вашего решения. 2: создать конкретный интерфейс ICatcher со специальным уловом метода и сделать что-то вроде:
AnimalFactory::animal_type type = AnimalFactory::animal_type::cat;
std::shared_ptr<IAnimal> animal = myAnimalFactory.createAnimal(type);
(dynamic_cast<ICatcher*>(animal.get()))->catch();
Но здесь вы должны быть уверены, что dynamic_cast будет успешным или предоставит дополнительную проверку для этого.
Возможно, вам также было бы интересно, как эта проблема будет решена в COM с помощью суперинтерфейса IUnknown и его метода QueryInterface. Возможно реализовать локальную версию для этой архитектуры.
Я не думаю, что вы можете на самом деле бросить из shared_ptr в Cat, не так ли? Поэтому без знания вашей базы кода я написал небольшую тестовую программу,
#include <memory>
#include <string>
#include <iostream>
class IAnimal
{
public:
virtual void makeSound(){}
};
class Cat : public IAnimal
{
public:
virtual void makeSound() { std::cout << "purr" << std::endl; }
void catchMice(void){
std::cout<<"mouse catched\n";
}
};
class Dog : public IAnimal
{
virtual void makeSound() { std::cout << "bark" << std::endl; }
};
int main(int argc,char** argv){
Cat* c = new Cat;
std::shared_ptr<IAnimal> s(c);
//you've basically got something of this sort don't you?
s->makeSound();
(static_cast<Cat*>(s.get()))->catchMice();
return 0;
}
который должен делать то, что вы хотите. Я считаю, что вы можете иметь makeSound (void) как виртуальную функцию.
find_food
,collect_food
,consume_food
должно быть достаточно.makeSound
выглядит как виртуальная функция.