如何处理 class 及其属性的抽象和专业化?
How to handle abstraction and specialization of a class and its attributes?
为这个相当抽象的标题道歉。
更清楚:
- 我有两个classes
Controler
和Interface
(硬件意义,与设计模式无关)
- 两者都是抽象的,带有一些纯虚方法,因此打算被子classed
- 我需要创建的每个
Controler
都与 Interface
object 相关联
- 每个
Controler
subclass 仅适用于 Interface
subclasses 的一个子集(ControlerA + InterfaceA
或 ControlerB + InterfaceB
而不是 ControlerA + InterfaceB
)
- 每个
Interface
子class都有自己的方法不继承(这就是为什么只有一种Controler
可以使用它)
Controler
基class需要调用基classInterface
的一些方法
我尝试将 Interface
对象传递给 Controler
构造函数,因此在我的 class 定义中 Interface
属性表示抽象基础 class .但是如果我的 Controler
subclass A 需要调用 Interface
A 的特定方法,则会引发编译错误,因为 Interface
base class does'我没有这个方法。
我找到的唯一解决方法是调用 dynamic_cast
,但显然它似乎是错误的。
这是我的 Interface
classes:
class Interface {
public:
Interface() {};
virtual void method() = 0;
};
class InterfaceA : public Interface {
public:
InterfaceA() : Interface() {};
void method() override { cout << "A overriding" << endl; }
void onlyA() { cout << "A only" << endl; }
};
class InterfaceB : public Interface {
public:
InterfaceB() : Interface() {};
void method() override { cout << "B overriding" << endl; }
void onlyB() { cout << "B only" << endl; }
};
这是我的 Controler
classes:
class Controler {
public:
Controler(Interface* i) : m_interface(i) {};
virtual void uniqueMethod() = 0;
void commonMethod() { m_interface->method(); }
Interface* m_interface;
};
class ControlerA : public Controler {
public:
ControlerA(InterfaceA* i) : Controler(i) {};
void uniqueMethod() override {dynamic_cast<InterfaceA *>(m_interface)->onlyA();}
};
class ControlerB : public Controler {
public:
ControlerB(InterfaceB* i) : Controler(i) {};
void uniqueMethod() override {dynamic_cast<InterfaceB *>(m_interface)->onlyB();}
};
下面是我打算如何使用它们:
auto ia = new InterfaceA();
auto ca = ControlerA(ia);
ca.commonMethod(); // Method defined in the base class
ca.uniqueMethod(); // Method defined in InterfaceA only
您可以在 Repl.it 上试用。
有什么设计模式可以解决这个问题吗?
确实有问题。 m_interface
的动态类型与实现Controler
的对象的动态类型之间存在不变量。但是Controler
class无法维持这个不变量。所以 m_interface
成员不是正确的地方。
结果是每次调用 uniqueMethod
时都需要使用 dynamic_cast
在运行时检查此成员是否具有正确的类型。如果不变量被破坏,代码将具有 UB,因为它会取消引用空指针。
所以这不是真正的设计模式问题,而是更根本的面向对象编程建议:classes 必须确保不变量。
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>;
为这个相当抽象的标题道歉。
更清楚:
- 我有两个classes
Controler
和Interface
(硬件意义,与设计模式无关) - 两者都是抽象的,带有一些纯虚方法,因此打算被子classed
- 我需要创建的每个
Controler
都与Interface
object 相关联
- 每个
Controler
subclass 仅适用于Interface
subclasses 的一个子集(ControlerA + InterfaceA
或ControlerB + InterfaceB
而不是ControlerA + InterfaceB
) - 每个
Interface
子class都有自己的方法不继承(这就是为什么只有一种Controler
可以使用它) Controler
基class需要调用基classInterface
的一些方法
我尝试将 Interface
对象传递给 Controler
构造函数,因此在我的 class 定义中 Interface
属性表示抽象基础 class .但是如果我的 Controler
subclass A 需要调用 Interface
A 的特定方法,则会引发编译错误,因为 Interface
base class does'我没有这个方法。
我找到的唯一解决方法是调用 dynamic_cast
,但显然它似乎是错误的。
这是我的 Interface
classes:
class Interface {
public:
Interface() {};
virtual void method() = 0;
};
class InterfaceA : public Interface {
public:
InterfaceA() : Interface() {};
void method() override { cout << "A overriding" << endl; }
void onlyA() { cout << "A only" << endl; }
};
class InterfaceB : public Interface {
public:
InterfaceB() : Interface() {};
void method() override { cout << "B overriding" << endl; }
void onlyB() { cout << "B only" << endl; }
};
这是我的 Controler
classes:
class Controler {
public:
Controler(Interface* i) : m_interface(i) {};
virtual void uniqueMethod() = 0;
void commonMethod() { m_interface->method(); }
Interface* m_interface;
};
class ControlerA : public Controler {
public:
ControlerA(InterfaceA* i) : Controler(i) {};
void uniqueMethod() override {dynamic_cast<InterfaceA *>(m_interface)->onlyA();}
};
class ControlerB : public Controler {
public:
ControlerB(InterfaceB* i) : Controler(i) {};
void uniqueMethod() override {dynamic_cast<InterfaceB *>(m_interface)->onlyB();}
};
下面是我打算如何使用它们:
auto ia = new InterfaceA();
auto ca = ControlerA(ia);
ca.commonMethod(); // Method defined in the base class
ca.uniqueMethod(); // Method defined in InterfaceA only
您可以在 Repl.it 上试用。
有什么设计模式可以解决这个问题吗?
确实有问题。 m_interface
的动态类型与实现Controler
的对象的动态类型之间存在不变量。但是Controler
class无法维持这个不变量。所以 m_interface
成员不是正确的地方。
结果是每次调用 uniqueMethod
时都需要使用 dynamic_cast
在运行时检查此成员是否具有正确的类型。如果不变量被破坏,代码将具有 UB,因为它会取消引用空指针。
所以这不是真正的设计模式问题,而是更根本的面向对象编程建议:classes 必须确保不变量。
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>;