Körkörös függőség

A Wikipédiából, a szabad enciklopédiából

A számítógép-programozásban a körkörös függőség egy modulok közötti kapcsolat, amelyek közvetve vagy közvetlenül kölcsönösen függenek egymástól. Az ilyen modulokat kölcsönösen rekurzívnak nevezik.

A körkörös függőség sok tartománymodellben természetes, ahol egy tartomány objektumai függenek egymástól. Azonban a nagyobb modulok közötti kölcsönös függőség antiminta, negatív hatásai miatt. A funkcionális programozásban azonban a kölcsönösen rekurzív modulok elfogadottak, mivel a paradigma támogatja a rekurzív és induktív definíciókat.

Következményei[szerkesztés]

A kölcsönös függőségnek számos negatív következménye lehet. Az egyik legfontosabb a szoros csatolás, ami megnehezíti, vagy akár lehetetlenné teszi, hogy egy modult önállóan is fel lehessen használni.

Körkörös függőség fennálláskor az egyik modul kis változása továbbterjed más modulokba, végül globális hatásai lesznek. Végtelen rekurziót, váratlan hibákat is eredményezhet.

A körkörösen függő struktúrák akadályozzák az egyszerű, hivatkozásszámláló szemétgyűjtőket, így memóriaszivárgást okoznak.

Okai és megoldása[szerkesztés]

Nagyobb rendszerekben, amiket egy ember már nem lát át, a csapat tagjai kölcsönösen hivatkozhatnak egymás moduljaira. Ezen elemző eszközök segíthetnek, amelyek figyelmeztetést adnak, és megmutatják a kölcsönös függést.[1] Egy megoldás a modulok összevonása.

A visszahívás funkció megvalósítása is okozhat kölcsönös függőséget. Ezt programtervezési minták, például a megfigyelő oldhatják meg.

Példák[szerkesztés]

C/C++ példa[szerkesztés]

C-ben és C++-ban trükkös a kölcsönös függőség megvalósítása, mivel minden rekordot vagy osztályt csak azután lehet használni, miután definiálták. A definíció lehet ugyanabban a fájlban, vagy include-olva egy másik fájlból. Ha a fájlok kölcsönösen include-olják egymást, akkor az hibát okoz. Ezen az előredeklarálással lehet segíteni.

  • a.h:
#ifndef A_H
#define A_H

class B;	//előredeklarálás

class A {
public:
	B* b;
};
#endif //A_H
  • b.h:
#ifndef B_H
#define B_H
 
class A;	//előredeklarálás

class B {
public:
	A* a;
};
#endif //B_H
  • main.cpp:
#include "a.h"
#include "b.h"
 
int main() {
	A a;
	B b;
	a.b = &b;
	b.a = &a;
}

Jegyezzük meg, hogy egy nevet többször lehet deklarálni, de csak egyszer lehet definiálni.

Önhivatkozó példa[szerkesztés]

Az előredeklarálás hasznos különféle adatstruktúrák, láncolt listák, fák megadásához is.

  • a.h:
class A {
public:
    static A *first, *last;
    A *previous, *next;

    A();
    ~A();
};

A first és last static változókat definiálni kell, mivel a deklaráció nem foglal nekik helyet a memóriában. Jegyezzük meg, hogy a static változók osztályszintűek, nem változnak objektumonként.

  • a.cpp:
#include "a.h"

A *A::first=0, *A::last=0; // ne írd ide a static szót, hibát okoz

A::A() {
    if(first==0) first=this; //first A létrehozása
    previous=last;
    if(previous != 0) previous->next=this;
    last=this;
    next=0;
}

A::~A() {
    if(previous != 0) previous->next=next;
    if(next != 0) next->previous=previous;
}

Jegyzetek[szerkesztés]

Fordítás[szerkesztés]

Ez a szócikk részben vagy egészben a Circular dependency című angol Wikipédia-szócikk fordításán alapul. Az eredeti cikk szerkesztőit annak laptörténete sorolja fel. Ez a jelzés csupán a megfogalmazás eredetét és a szerzői jogokat jelzi, nem szolgál a cikkben szereplő információk forrásmegjelöléseként.