在构成的情况下访问“内部”类

时间:2014-07-17 07:49:33

标签: c++ design-patterns architecture composition

我将某些功能封装在我在另一个类中使用的类中。我认为这叫做作文。

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和/或functionality02DoesSomething01和/或DoesSomething02我看到两种可能性:

a)将此类方法添加到ClassA,以便ClassB直接访问DoesSomething01和/或DoesSomething02

DoesSomething01 *getDoesSomething01() { return *m_doesSomething01; }
DoesSomething02 *getDoesSomething02() { return *m_doesSomething02; }

ClassB可以这样做:

m_classA->getDoesSomething01()->functionality01();

b)向ClassA添加(在本例中为四种)方法,将方法调用转发给DoesSomething01DoesSomething02,如下所示:

void doesSomething01Functionality01() { m_doesSomething01->functionality01(); }
void doesSomething01Functionality02() { m_doesSomething01->functionality02(); }
void doesSomething02Functionality01() { m_doesSomething02->functionality01(); }
void doesSomething02Functionality02() { m_doesSomething02->functionality02(); }

哪个选项更好,为什么?

每个选项的优点/缺点是什么?

4 个答案:

答案 0 :(得分:1)

第一个选项可以被视为代码气味。根据罗伯特C.马丁的'Clean Code',它是"传递导航"应该避免。引用作者:

  

一般来说,我们不希望单个模块对其了解太多   合作者。更具体地说,如果A与B和B合作   与C合作,我们不希望使用A的模块知道C.   (例如,我们不想要a.getB()。getC()。doSomething();.)

第二个选项看起来更好。它是Facade模式的经典用法。它更好,因为它隐藏了类DoesSomthing01DoesSomthing02的其他功能。然后你得到了简化的视图,比第一个选项更容易使用。

编辑:还有一件事。您有两个具有相同功能的类,并由其他类聚合。你应该考虑在这里使用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个对象之间的通信。