我将某些功能封装在我在另一个类中使用的类中。我认为这叫做作文。
class DoesSomething01
{
public:
DoesSomething01();
void functionality01();
void functionality02();
};
class DoesSomething02
{
public:
DoesSomething02();
void functionality01();
void functionality02();
};
class ClassA
{
public:
ClassA();
private:
DoesSomething01 *m_doesSomething01;
DoesSomething02 *m_doesSomething02;
};
如果我现在有ClassB
“知道”ClassA
并且必须使用/执行functionality01
和/或functionality02
类DoesSomething01
和/或DoesSomething02
我看到两种可能性:
a)将此类方法添加到ClassA
,以便ClassB
直接访问DoesSomething01
和/或DoesSomething02
:
DoesSomething01 *getDoesSomething01() { return *m_doesSomething01; }
DoesSomething02 *getDoesSomething02() { return *m_doesSomething02; }
ClassB
可以这样做:
m_classA->getDoesSomething01()->functionality01();
b)向ClassA
添加(在本例中为四种)方法,将方法调用转发给DoesSomething01
和DoesSomething02
,如下所示:
void doesSomething01Functionality01() { m_doesSomething01->functionality01(); }
void doesSomething01Functionality02() { m_doesSomething01->functionality02(); }
void doesSomething02Functionality01() { m_doesSomething02->functionality01(); }
void doesSomething02Functionality02() { m_doesSomething02->functionality02(); }
哪个选项更好,为什么?
每个选项的优点/缺点是什么?
答案 0 :(得分:1)
第一个选项可以被视为代码气味。根据罗伯特C.马丁的'Clean Code',它是"传递导航"应该避免。引用作者:
一般来说,我们不希望单个模块对其了解太多 合作者。更具体地说,如果A与B和B合作 与C合作,我们不希望使用A的模块知道C. (例如,我们不想要a.getB()。getC()。doSomething();.)
第二个选项看起来更好。它是Facade模式的经典用法。它更好,因为它隐藏了类DoesSomthing01
和DoesSomthing02
的其他功能。然后你得到了简化的视图,比第一个选项更容易使用。
编辑:还有一件事。您有两个具有相同功能的类,并由其他类聚合。你应该考虑在这里使用Stratey pattern。您的代码将如下所示:
class DoesSomething
{
public:
virtual void functionality01() = 0;
virtual void functionality02() = 0;
}
class DoesSomething01 : DoesSomething
{
public:
DoesSomething01();
void functionality01();
void functionality02();
};
class DoesSomething02 : DoesSomething
{
public:
DoesSomething02();
void functionality01();
void functionality02();
};
class ClassA
{
public:
ClassA();
DoesSomething* doesSomething(); // Getter
void doesSomething(DoesSomething* newDoesSomething); // Setter
// ...
private:
DoesSomething *m_doesSomething;
};
然后你只需要两种方法而不是四种方法:
void doesFunctionality01() { m_doesSomething->functionality01(); }
void doesFunctionality02() { m_doesSomething->functionality02(); }
答案 1 :(得分:1)
第一种情况违反了德米特的法律,该法律规定一个班级只能与其直接的朋友交谈。基本上第一种方法的问题是内部类DoSomething01和DoSomething02的任何更改都会触发A类和B类的更改,因为这两个类现在都直接依赖于这些内部类。
第二个选项更好,因为它从内部类封装了B类,但是这个解决方案的副作用是现在A类有很多方法,除了委托给它的内部类之外什么都不做。这很好,但想象一下,如果DoSomething01有一个内部类DoSomething03并且B类需要访问它的功能而不直接了解它,那么A类需要有另一个委托给DoSomething01的方法,而DoSomething01又会委托给DoSomething03。在这种情况下,我认为最好让B类直接了解DoSomething01,否则A类将拥有一个巨大的接口,只需委托给它的内部类。
答案 2 :(得分:0)
如果要调用许多类和/或许多方法,那么发明是有意义的 一个抽象父类形式的接口:
class SomeInterface
{
public:
SomeInterface(){}
virtual void functionally01() = 0;
virtual void functionally02() = 0;
}
然后,DoesSomthing01和其他类将继承此类:
class DoesSomthing01 : public SomeInterface
并实施方法。
如果将密钥与此类的实例化相关联是有意义的 你可以在ClassA中存储这些对象,例如使用地图(这里我 使用整数作为键):
class ClassA
{
private:
std::map<int, SomeInterface*> m_Interfaces;
public:
SomeInterface* getInterface(const int key)
{
std::map<int, SomeInterface*>::iterator it(m_Interfaces.find(key));
if (it != m_Interfaces.end())
return it->second;
else
return NULL;
}
};
然后你可以从ClassB访问它们
int somekey = ...;
SomeInterface *myInter = m_classA->getInterface(somekey);
if (myInter)
myInter->functionally01();
这样,您只有一个访问方法(getInterface())独立 对象的数量。
为了使用密钥对方法的访问进行编码 创建一个映射,将键映射到闭包或简单的switch语句: 在SomeInterface中:
public:
void executeMethod(const int key)
{
switch(key)
{
case 1: functionally01(); break;
case 2: functionally01(); break;
default:
// error
}
int methodKey = ...;
int objectKey = ...;
SomeInterface *myInter = m_classA->getInterface(objectKey);
if (myInter)
myInter->executeMethod(methodKey);
答案 3 :(得分:0)
看起来像Mediator Pattern的好例子。
此模式管理他拥有的2个对象之间的通信。