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.[1]

DefinícióSzerkesztés

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).[1]

AlkalmazhatóságSzerkesztés

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).[1]

StruktúraSzerkesztés

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.[1]

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

[1]

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ó:

[1]

EgyüttműködésekSzerkesztés

  • 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é.[1]
  • 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.[1]
  • 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.[1]

Példa kódSzerkesztés

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

[1]

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

[1]

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

[1]

Iker minta megvalósításaSzerkesztés

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.[1][2]

JegyeztekSzerkesztés

  1. a b c d e f g h i j k l m Mössenböck, H., Twin - A Design Pattern for Modelling Multiple Inheritance, University of Linz, Institute for System Software
  2. Stroustrup, B. (May 1989), Multiple Inheritance for C++, Helsinki: Proceeding EUUG Spring Conference

FordításSzerkesztés

Ez a szócikk részben vagy egészben a Twin Pattern című angol Wikipédia-szócikk ezen változatának fordításán alapul. Az eredeti cikk szerkesztőit annak laptörténete sorolja fel.