Проблема действительно есть.Существует инвариант между динамическим типом m_interface
и динамическим типом объекта, который реализует Controler
.Но этот инвариант не может поддерживаться классом Controler
.Таким образом, элемент m_interface
не является правильным местом.
Следствием этого является необходимость проверки во время выполнения, чтобы этот элемент имел правильный тип, используя dynamic_cast
каждый раз, когда вы вызываете uniqueMethod
.Если инвариант не работает, в коде будет UB, поскольку он будет разыменовывать нулевой указатель.
Так что на самом деле это не проблема шаблона проектирования, а, в сущности, рекомендация объектно-ориентированного программирования: классы должны обеспечиватьинварианты.
class Controler {
public:
virtual void uniqueMethod() = 0;
virtual void commonMethod() = 0;
};
class ControlerA : public Controler {
public:
ControlerA(InterfaceA* i):m_interface{i} {
assert(dynamic_cast<InterfaceA*>(i)!=nullptr);
};
void uniqueMethod() override { m_interface->onlyA();}
void commonMethod() override { m_interface->method(); }
private: InterfaceA* m_interface;
};
class ControlerB : public Controler {
public:
ControlerB(InterfaceB* i):m_interface{i} {
assert(dynamic_cast<InterfaceB*>(i)!=nullptr);
};
void uniqueMethod() override { m_interface->onlyB();}
void commonMethod() override { m_interface->method(); }
private: InterfaceB* m_interface;
};
Итак, похоже, у нас есть регулярный шаблон, поэтому мы можем подумать о более общем дизайне:
template<class Inter,void(Inter::* OnlyFunc)()>
class ControlerImpl : public Controler {
public:
ControlerImpl(Inter* i):m_interface{i} {
assert(dynamic_cast<Inter*>(i)!=nullptr);
};
void uniqueMethod() override { (m_interface->*OnlyFunc)();}
void commonMethod() override { m_interface->method(); }
private: Inter* m_interface;
};
using ControlerA = ControlerImpl<InterfaceA,&InterfaceA::onlyA>;
using ControlerB = ControlerImpl<InterfaceB,&InterfaceB::onlyB>;