Iker programtervezési minta
A szoftverfejlesztésben, az iker minta egy programtervezési minta, ami lehetővé teszi a fejlesztőknek, hogy megvalósíthassák a többszörös öröklődést, olyan programozási nyelvekben, amik ezt nem támogatják. A mintával elkerülhetjük a többszörös öröklődéssel kapcsolatos problémák nagy részét.

Definíció 
Ahelyett, hogy létrehoznánk egy osztályt ami két szülő-osztályból származik, hozzunk létre inkább két külön gyerek-osztályt, egyiket az egyik, másikat a másik szülő-osztályból örökítve. A gyerek-osztályok szorosan csatoltak, így együttesen egy „iker objektumként“ tekinthetünk rájuk, aminek két külön felülete van (egy az egyik szülőtől származó funkcionalitáshoz, egy pedig a másik szülőtől származóhoz).

Alkalmazhatóság 
Az Iker programtervezési mintát használhatjuk:
 többszörös öröklődés megvalósításához, olyan nyelvekben ahol ez nem támogatott;
 néhány többszörös öröklődésből adódó probléma elkerülésére (mint például a szülő-osztályok tagjai közötti név ütközések).

Struktúra 
Lesz két vagy több szülő-osztály, amit örökíteni akarunk. Mindegyikhez lesz egy gyerek-osztály, ami a szülő-osztályok egyikéből származik. A gyerek-osztályok kölcsönösen össze vannak kapcsolva mezők segítségével (csatoltság), és bármely gyerek-osztály felülírhatja a szülő-osztályból örökölt metódusait. Új metódusokat és mezőket általában csak a gyerekosztályok egyikében deklarálunk.

A következő diagram a többszörös öröklődés tipikus struktúráját mutatja: 

Az alábbi diagramon pedig az (előzőleg bemutatott többszörös öröklődést kiváltó) iker minta struktúrája látható:

Együttműködések
 Minden gyerek-osztály felelős a szülő-osztályától örökölt protokollért. A gyerek kezeli az ehhez a protokollhoz tartozó üzeneteket, az egyéb üzeneteket pedig továbbítja a társ osztálya felé.
 Az iker minta kliensei csak az iker objektumok egyikére hivatkoznak közvetlenül, a többire (testvérek) pedig ennek az objektumnak a mezőin keresztül.
 A kliensek, amik a szülő osztályok protokolljaira támaszkodnak, az adott szülőnek megfelelő (abból származtatott) gyerek-osztály objektumaival kommunikálnak.

Példa kód
A következő kód, egy mozgó golyókkal működő számítógépes táblajáték implementációjának vázlata.

a játéktáblához tartozó osztály:
 
public class Gameboard extends Canvas {
 public int width, height;
 public GameItem firstItem;
 …
}

kódvázlat a GameItem (játékelem) osztályhoz:
public abstract class GameItem {
 Gameboard board;
 int posX, posY;
 GameItem next;
 public abstract void draw();
 public abstract void click (MouseEvent e);
 public abstract boolean intersects (GameItem other);
 public abstract void collideWith (GameItem other);
 public void check() {
  GameItem x;
  for (x = board.firstItem; x != null; x = x.next)
   if (intersects(x)) collideWith(x);
 }
 public static BallItem newBall
  (int posX, int posY, int radius) {//method of GameBoard
   BallItem ballItem = new BallItem(posX, posY, radius);
   BallThread ballThread = new BallThread();
   ballItem.twin = ballThread;
   ballThread.twin = ballItem;
   return ballItem;
 }
}
kódvázlat a  BallItem (golyó) osztályhoz:
public class BallItem extends GameItem {
 BallThread twin;
 int radius; int dx, dy;
 boolean suspended;
 public void draw() {
  board.getGraphics().drawOval(posX-radius, posY-radius, 2*radius, 2*radius); }
 public void move() { posX += dx; posY += dy; }
 public void click() {
  if (suspended) twin.resume(); else twin.suspend();
  suspended = ! suspended;
 }
 public boolean intersects (GameItem other) {
  if (other instanceof Wall)
   return posX - radius <= other.posX
    && other.posX <= posX + radius
   || posY - radius <= other.posY
    && other.posY <= posY + radius;
  else return false;
 }
 public void collideWith (GameItem other) {
  Wall wall = (Wall) other;
  if (wall.isVertical) dx = - dx; else dy = - dy; }}

kódvázlat a  BallThread („golyómozgató“ programszál) osztályhoz:
public class BallThread extends Thread {
 BallItem twin;
 public void run() {
  while (true) {
   twin.draw(); /*erase*/ twin.move(); twin.draw();
  }
 }
}

Iker minta megvalósítása
A következő szempontokat érdemes figyelembe venni:

 Adat absztrakció - az „iker osztály“ együttműködő osztályai (testvérek) erősen csatoltak kell hogy legyenek, mivel valószínűleg el kell tudniuk érni egymás privát mezőit és metódusait. Java-ban ezt úgy érhetjük el, hogy a testvér osztályokat egy közös csomagba (package) rakjuk, és csomag szintű láthatóságot adunk a szükséges mezőknek és metódusoknak. Modula-3-ban és Oberon-ban az együttműködő osztályok egy közös modulba kerülhetnek.
 Hatékonyság - Az iker minta kompozíciót használ, ami üzenet-továbbítást igényel, emiatt az iker minta kevésbé hatékony lehet, mint az öröklődés. Mivel azonban a többszörös öröklődés némileg kevésbé hatékony mint az egyszeres öröklődés, az üzenet továbbításból fakadó többlet munka nem okoz komoly problémát.

Jegyzetek

Fordítás

Programtervezési minták
Java-kódpéldák
A szoftverfejlesztésben , az iker minta egy programtervezési minta , ami lehetővé teszi a fejlesztőknek , hogy megvalósíthassák a többszörös öröklődést , olyan programozási nyelvekben , amik ezt nem támogatják . A mintával elkerülhetjük a többszörös öröklődéssel kapcsolatos problémák nagy részét . Definíció Ahelyett , hogy létrehoznánk egy osztályt ami két szülő-osztályból származik , hozzunk létre inkább két külön gyerek-osztályt , egyiket az egyik , másikat a másik szülő-osztályból örökítve . A gyerek-osztályok szorosan csatoltak , így együttesen egy „ iker objektumként“ tekinthetünk rájuk , aminek két külön felülete van ( egy az egyik szülőtől származó funkcionalitáshoz , egy pedig a másik szülőtől származóhoz ) . Alkalmazhatóság Az Iker programtervezési mintát használhatjuk : többszörös öröklődés megvalósításához , olyan nyelvekben ahol ez nem támogatott ; néhány többszörös öröklődésből adódó probléma elkerülésére ( mint például a szülő-osztályok tagjai közötti név ütközések ) . Struktúra Lesz két vagy több szülő-osztály , amit örökíteni akarunk . Mindegyikhez lesz egy gyerek-osztály , ami a szülő-osztályok egyikéből származik . A gyerek-osztályok kölcsönösen össze vannak kapcsolva mezők segítségével ( csatoltság ) , és bármely gyerek-osztály felülírhatja a szülő-osztályból örökölt metódusait . Új metódusokat és mezőket általában csak a gyerekosztályok egyikében deklarálunk . A következő diagram a többszörös öröklődés tipikus struktúráját mutatja : Az alábbi diagramon pedig az ( előzőleg bemutatott többszörös öröklődést kiváltó ) iker minta struktúrája látható : Együttműködések Minden gyerek-osztály felelős a szülő-osztályától örökölt protokollért . A gyerek kezeli az ehhez a protokollhoz tartozó üzeneteket , az egyéb üzeneteket pedig továbbítja a társ osztálya felé . Az iker minta kliensei csak az iker objektumok egyikére hivatkoznak közvetlenül , a többire ( testvérek ) pedig ennek az objektumnak a mezőin keresztül . A kliensek , amik a szülő osztályok protokolljaira támaszkodnak , az adott szülőnek megfelelő ( abból származtatott ) gyerek-osztály objektumaival kommunikálnak . Példa kód A következő kód , egy mozgó golyókkal működő számítógépes táblajáték implementációjának vázlata. a játéktáblához tartozó osztály : public class Gameboard extends Canvas { public int width , height ; public GameItem firstItem ; … } kódvázlat a GameItem ( játékelem ) osztályhoz : public abstract class GameItem { Gameboard board ; int posX , posY ; GameItem next ; public abstract void draw ( ) ; public abstract void click ( MouseEvent e ) ; public abstract boolean intersects ( GameItem other ) ; public abstract void collideWith ( GameItem other ) ; public void check ( ) { GameItem x ; for ( x = board.firstItem ; x != null ; x = x.next ) if ( intersects ( x ) ) collideWith( x ) ; } public static BallItem newBall ( int posX , int posY , int radius ) { //method of GameBoard BallItem ballItem = new BallItem( posX , posY , radius ) ; BallThread ballThread = new BallThread ( ) ; ballItem.twin = ballThread ; ballThread.twin = ballItem ; return ballItem ; } } kódvázlat a BallItem ( golyó ) osztályhoz : public class BallItem extends GameItem { BallThread twin ; int radius ; int dx , dy ; boolean suspended ; public void draw ( ) { board.getGraphics ( ) .drawOval( posX-radius , posY-radius , radius , radius ) ; } public void move ( ) { posX += dx ; posY += dy ; } public void click ( ) { if ( suspended ) twin.resume ( ) ; else twin.suspend ( ) ; suspended = ! suspended ; } public boolean intersects ( GameItem other ) { if ( other instanceof Wall ) return posX - radius <= other.posX & & other.posX <= posX + radius || posY - radius <= other.posY & & other.posY <= posY + radius ; else return false ; } public void collideWith ( GameItem other ) { Wall wall = ( Wall ) other ; if ( wall.isVertical ) dx = - dx ; else dy = - dy ; } } kódvázlat a BallThread ( „ golyómozgató“ programszál ) osztályhoz : public class BallThread extends Thread { BallItem twin ; public void run ( ) { while ( true ) { twin.draw ( ) ; / *erase * / twin.move ( ) ; twin.draw ( ) ; } } } Iker minta megvalósítása A következő szempontokat érdemes figyelembe venni : Adat absztrakció - az „ iker osztály“ együttműködő osztályai ( testvérek ) erősen csatoltak kell hogy legyenek , mivel valószínűleg el kell tudniuk érni egymás privát mezőit és metódusait . Java-ban ezt úgy érhetjük el , hogy a testvér osztályokat egy közös csomagba ( package ) rakjuk , és csomag szintű láthatóságot adunk a szükséges mezőknek és metódusoknak . Modula-3-ban és Oberon-ban az együttműködő osztályok egy közös modulba kerülhetnek . Hatékonyság - Az iker minta kompozíciót használ , ami üzenet-továbbítást igényel , emiatt az iker minta kevésbé hatékony lehet , mint az öröklődés . Mivel azonban a többszörös öröklődés némileg kevésbé hatékony mint az egyszeres öröklődés , az üzenet továbbításból fakadó többlet munka nem okoz komoly problémát . Jegyzetek Fordítás Programtervezési minták Java-kódpéldák