簡體   English   中英

組成時可進入“內部”課程

[英]Access to 'inner' classes in case of 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;
};

如果我現在擁有一個“知道” ClassAClassB ,並且必須使用/執行DoesSomething01和/或DoesSomething02類的functionality01和/或functionality02 DoesSomething01DoesSomething02我會看到兩種可能性:

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(); }

哪個選項更好,為什么?

每個選項的優點/缺點是什么?

第一選擇可以被認為是代碼氣味。 根據羅伯特·C·馬丁(Robert C. Martin)的“清潔代碼”,它是“傳遞式導航”,應避免使用。 引用作者:

通常,我們不希望單個模塊對其協作者有太多了解。 更具體地說,如果A與B合作,而B與C合作,我們不希望使用A的模塊了解C。(例如,我們不希望a.getB()。getC()。doSomething( );.)

第二種選擇看起來更好。 這是Facade模式的經典用法。 並且更好,因為它隱藏了類DoesSomthing01DoesSomthing02其他功能。 然后,您獲得了簡化視圖,它比第一個選項更易於使用。

編輯:還有另外一件事。 您有兩個具有相同功能的類,並由其他類聚合。 您應該在這里考慮使用Stratey模式 您的代碼將如下所示:

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(); }

第一種情況是違反了Demeter的法律,Demeter認為一個班級只能與其直接的朋友交談。 基本上,第一種方法的問題是內部類DoSomething01和DoSomething02的任何更改都會觸發類A和類B的更改,因為這兩個類現在都直接依賴於這些內部類。

第二種方法更好,因為它封裝了內部類中的類B,但是此解決方案的副作用是,現在類A有很多方法,除了委派給其內部類外別無所求。 這很好,但是可以想象一下,如果DoSomething01具有內部類DoSomething03,並且類B需要在不直接了解其功能的情況下訪問其功能,而不是類A需要具有另一個將委托給DoSomething01的方法,該方法又將委托給DoSomething03。 在這種情況下,我認為最好讓B類直接了解DoSomething01,否則A類將具有一個巨大的接口,可以簡單地委派給其內部類。

如果要調用許多類和/或許多方法,那么以抽象父類的形式發明一個接口是有意義的:

class SomeInterface
{
    public:
    SomeInterface(){}

    virtual void functionally01() = 0;
    virtual void functionally02() = 0;
}

然后,DosSomthing01和其他類將繼承該類:

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);

看起來是中介模式的一個很好的例子。

此模式管理他擁有的2個對象之間的通信。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM