RSS

Zaprzyjaźnianie klas: Java i C++

Liczba odsłon: 1351

W ję­zy­kach Java oraz C++ ist­nie­je moż­li­wość na­da­wa­nia kla­som praw do ko­rzy­sta­nia z ca­łej funkcjo­nal­noś­ci in­nych klas z po­mi­nię­ciem war­stwy her­me­ty­za­cji. Mechanizm ta­ki, na­zy­wa­ny za­przy­jaź­nia­niem klas, jest jed­nak w oby­dwu tych ję­zy­kach zrea­li­zo­wa­ny na dwa róż­ne spo­so­by.

Wbrew po­zo­rom, za­przy­jaź­nia­nie po­zwa­la zwięk­szyć sto­pień her­me­ty­za­cji bi­blio­te­ki klas. Dzięki te­mu me­cha­niz­mo­wi, kla­sy reali­zu­ją­ce wspól­nie pew­ną funkcjo­nal­ność mo­gą ko­rzy­stać ze wszyst­kich swo­ich moż­li­woś­ci, z peł­ną zna­jo­mo­ścią szcze­gółów im­ple­men­ta­cyj­nych, bez ko­niecz­noś­ci two­rze­nia spe­cjal­ne­go, pub­licz­ne­go inter­fej­su, któ­ry eks­po­no­wał­by nie­któ­re, po­trzeb­ne im ele­men­ty.

Zaprzyjaź­nia­nie w ję­zy­ku C++

W ję­zy­ku C++ kla­sa mo­że być za­przy­jaź­nio­na z pod­pro­gra­mem lub in­ną kla­są. Zaprzyjaź­nie­nie na­stę­pu­je jaw­nie, przez uży­cie sło­wa klu­czo­we­go friend:

class Klasa
{
private:
   friend void podprogram(Klasa &obiekt);
   friend class Zaprzyjazniona;
   void metoda();
};

void podprogram(Klasa &obiekt)
{
   obiekt.metoda();
}

class Zaprzyjazniona
{
public:
   void metoda(Klasa &obiekt)
   {
      obiekt.metoda();
   }
};

Taka me­to­da za­przy­jaź­nia­nia jest bar­dzo wy­god­na, ma jed­nak pew­ne ce­chy oraz ogra­ni­cze­nia, o któ­rych na­le­ży pa­mię­tać:

  1. Zaprzyjaź­nie­nie do­ty­czy wszyst­kich ele­men­tów kla­sy, włącz­nie z pry­wat­ny­mi (pri­vate). Z punk­tu wi­dze­nia po­praw­noś­ci her­me­ty­za­cji by­ło­by le­piej, gdy­by do­ty­czy­ło tyl­ko ele­men­tów chro­nio­nych (pro­tec­ted). Nie ma pros­te­go spo­so­bu, by ukryć przed za­przy­jaź­nio­nym pod­pro­gra­mem lub kla­są część funkcjo­nal­noś­ci kla­sy.
  2. Zaprzyjaź­nie­nie nie jest dzie­dzicz­ne. Klasa po­chod­na wzglę­dem za­przy­jaź­nio­nej nie dzie­dzi­czy pod­wyż­szo­nych praw do­stę­pu do kla­sy do­ce­lo­wej.
  3. W przy­pad­ku bar­dziej skom­pli­ko­wa­nych szab­lo­nów, zde­fi­nio­wa­nie za­sad za­przy­jaź­nie­nia mo­że być trud­ne lub nie­moż­li­we.

Zaprzyjaź­nia­nie w ję­zy­ku Java

W ję­zy­ku Java kla­sa mo­że być za­przy­jaź­nio­na z in­ną kla­są. Zaprzyjaź­nie­nie na­stę­pu­je nie­jaw­nie, przez przy­na­leż­ność do te­go sa­me­go pa­kie­tu (pack­age) apli­kac­ji. Można też wska­zać po­la i me­to­dy, któ­re bę­dą wy­łą­czo­ne z za­przy­jaź­nie­nia: ozna­czo­ne atry­bu­tem pri­vate nie bę­dą pod­le­ga­ły za­przy­jaź­nie­niu, po­zba­wio­ne ja­kie­go­kol­wiek atry­bu­tu bę­dą pry­wat­ny­mi za­przy­jaź­nio­ny­mi (ang. pack­age-pri­vate), a ozna­czo­ne atry­bu­ta­mi pro­tec­tedpub­lic bę­dą do­stęp­ne na za­sa­dach ogól­nych.

package przykladowy;

class Klasa {
   int x;
   void metoda() {
   }
}

class Zaprzyjazniona {
   public void metoda(Klasa obiekt) {
      obiekt.x = 5;
      obiekt.metoda();
   }
}

Również ta tech­ni­ka za­przy­jaź­nia­nia ma pew­ne ce­chy, o któ­rych trze­ba pa­mię­tać:

  1. Nie ist­nie­je moż­li­wość za­przy­jaź­nie­nia klas znaj­du­ją­cych się w róż­nych pa­kie­tach. Nie moż­na za­tem po­dzie­lić więk­szej bi­blio­te­ki klas na pa­kie­ty pod­rzęd­ne w ce­lu utrzy­ma­nia we­wnętrz­ne­go ła­du.
  2. Wszystkie po­la i me­to­dy chro­nio­ne (pro­tec­ted) są auto­ma­tycz­nie do­stęp­ne w ra­mach pa­kie­tu na­wet, je­że­li in­ten­cją by­ło udos­tęp­nie­nie ich wy­łącz­nie kla­som po­chod­nym.

Pod­su­mo­wa­nie

Zaprzyjaź­nia­nia klas nie wol­no igno­ro­wać. Celem jest zaw­sze to, by pub­licz­nie był do­stęp­ny mi­ni­mal­ny zbiór me­tod nie­zbęd­nych do reali­zac­ji funkcjo­nal­noś­ci kla­sy. Wszystkie in­ne ele­men­ty mu­szą być ukry­te w moż­li­wie naj­bar­dziej sku­tecz­ny spo­sób.

Zaprzyjaź­nia­nie po­zwa­la zreali­zo­wać ta­kie ukry­wa­nie. Na przy­kład, dzię­ki za­przy­jaź­nie­niu kla­sy obiek­tu z kla­są fab­ry­ki mo­że­my wy­mu­sić two­rze­nie obiek­tów wy­łącz­nie za po­śred­nic­twem fab­ry­ki bez two­rze­nia nie­na­tu­ral­nych hie­rar­chii dzie­dzi­cze­nia. Podobnie, kla­sy im­ple­men­tu­ją­ce pew­ne wzor­ce pro­jek­to­we mo­gą dzię­ki za­przy­jaź­nie­niu uzys­ki­wać wy­łącz­ny do­stęp do de­dy­ko­wa­nych im me­tod klas koń­co­wych (choć ten ro­dzaj za­przy­jaź­nie­nia jest moż­li­wy w za­sa­dzie wy­łącz­nie w ję­zy­ku C++).