A számítógép-programozásban a kettős metódus a multimetódus speciális típusa. Programtervezési minta, ami mechanizmusként működve függvényhíváskor szükség esetén két paramétere szerint választ konkrét meghívandó függvényt. A legtöbb objektumorientált rendszer ebben csak egy paramétert képes figyelembe venni. Ezt virtuális függvénynek vagy egyszerű metódusnak nevezik.

Példák szerkesztés

A kettős metódus hasznos azokban a helyzetekben, amikor a számítás az objektumok konkrét típusától függ. Használható például a következő helyzetekben:

  • Vegyes objektumhalmaz rendezése. Objektumok egy listáját kell rendezni egy megadott kanonikus rendezés szerint. Mindkét típust ismerni kell ahhoz, hogy eldönthessük, hogy melyik melyik után következik.
  • Adaptív ütközési algoritmusok különböző objektumok között. Erre példa egy játék, amiben másként ütközik egy űrhajó egy aszteroidához, mint egy űrállomáshoz.[1]
  • Grafikai algoritmusok, amikben különbözőképpen kell megjeleníteni átfedéseket.
  • Munkaközvetítő rendszerek, amelyekben különböző munkákat különböző személyek között osztanak ki, így a rendszer nem ad hozzá egy könyvelőt egy olyan munkához, ahova mérnök kell.
  • Eseménykezelő rendszerek, ahol az esemény mellett a fogadó objektumot is ismerni kell.
  • Kulcs-zár rendszerek, ahol egy kulcs több zárat is nyithat. Azt is tudni kell, hogy melyik kulcs melyik zárat nyitja.

Megvalósítása szerkesztés

A meghívandó függvény kiválasztása attól függ, hogy milyen argumentumokkal hívják a kettős metódust; emiatt a hívás plusz költséget jelent, többet, mint amennyivel az egyszerű metódus. C++-ban a dinamikus függvényhívás egyetlen eltolás kiszámítását jelenti, amit a fordító az objektum metódustáblája alapján statikusan számol. Egy kettős metódusokat támogató nyelvben ezt dinamikusan kell megtenni.

Összehasonlítás a túlterheléssel szerkesztés

Első ránézésre a kettős metódus a túlterhelés természetes eredményének tűnik. A túlterhelés ugyanúgy lehetővé teszi a függvény kiválasztását az argumentumok típusa alapján. Azonban túlterhelés esetén fordítás időben statikusan lesz választva a függvény, belső neveket használva, amely belső nevek magukban foglalják az argumentumok típusát. Például a foo(int) függvény belső neve __foo_i , és a foo(double) belső neve __foo_d. Ezzel a fordító elkerüli a névütközést, és a virtuális tábla használatát. Ezzel szemben a kettős metódusok hívásakor virtuális függvények hívódnak meg, és ehhez a virtuális táblában kell keresni.

Az alábbi példa túlterhelést használ. A cél ütközések megvalósítása egy játékban:

class SpaceShip {};
class ApolloSpacecraft : public SpaceShip {};

class Asteroid {
public:
  virtual void CollideWith(SpaceShip&) {
    std::cout << "Asteroid hit a SpaceShip\n";
  }
  virtual void CollideWith(ApolloSpacecraft&) {
    std::cout << "Asteroid hit an ApolloSpacecraft\n";
  }
};

class ExplodingAsteroid : public Asteroid {
public:
  virtual void CollideWith(SpaceShip&) {
    std::cout << "ExplodingAsteroid hit a SpaceShip\n";
  }
  virtual void CollideWith(ApolloSpacecraft&) {
    std::cout << "ExplodingAsteroid hit an ApolloSpacecraft\n";
  }
};

Ha most:

Asteroid theAsteroid;
SpaceShip theSpaceShip;
ApolloSpacecraft theApolloSpacecraft;

akkor a túlterhelés miatt ez a kód:

theAsteroid.CollideWith(theSpaceShip); 
theAsteroid.CollideWith(theApolloSpacecraft);

rendre ezt írja ki: Asteroid hit a SpaceShip és Asteroid hit an ApolloSpacecraft Továbbá, az

ExplodingAsteroid theExplodingAsteroid;
theExplodingAsteroid.CollideWith(theSpaceShip); 
theExplodingAsteroid.CollideWith(theApolloSpacecraft);

kód futásának eredménye rendre ExplodingAsteroid hit a SpaceShip és ExplodingAsteroid hit an ApolloSpacecraft, szintén statikusan.

Ha az Asteroid közvetlen használat helyett referenciát kap, akkor dinamikusan lesz kiválasztva a metódus. Ez a kód

Asteroid& theAsteroidReference = theExplodingAsteroid;
theAsteroidReference.CollideWith(theSpaceShip); 
theAsteroidReference.CollideWith(theApolloSpacecraft);

kiírja, hogy ExplodingAsteroid hit a SpaceShip és ExplodingAsteroid hit an ApolloSpacecraft, úgy, ahogy vártuk. A következő kód azonban nem úgy működik, ahogy elvárnánk:

SpaceShip& theSpaceShipReference = theApolloSpacecraft;
theAsteroid.CollideWith(theSpaceShipReference);
theAsteroidReference.CollideWith(theSpaceShipReference);

Azt várnánk, hogy a függvény figyelembe veszi az argumentumok pontos típusát, vagyis az elvárt eredmény Asteroid hit an ApolloSpacecraft és ExplodingAsteroid hit an ApolloSpacecraft. Ehelyett azonban az jelenik meg, hogy Asteroid hit a SpaceShip és ExplodingAsteroid hit a SpaceShip. A problémát az jelenti, hogy a virtuális függvények kötése dinamikus, míg a túlterhelés statikus.

Kettős metódus C++-ban szerkesztés

A probléma megoldható a látogató programtervezési mintával. A fenti kódot kibővítjük a SpaceShip és a ApolloSpacecraft osztályokban a

virtual void CollideWith(Asteroid& inAsteroid) {
  inAsteroid.CollideWith(*this);
}

függvénnyel. A korrekt működéshez a hívó kódban a következőt kell tenni:

SpaceShip& theSpaceShipReference = theApolloSpacecraft;
Asteroid& theAsteroidReference = theExplodingAsteroid;
theSpaceShipReference.CollideWith(theAsteroid);
theSpaceShipReference.CollideWith(theAsteroidReference);

Ez most már azt írja, amit kell: Asteroid hit an ApolloSpacecraft és ExplodingAsteroid hit an ApolloSpacecraft A kulcs az, hogy theSpaceShipReference.CollideWith(theAsteroidReference); a következőképpen alakul: theSpaceShipReference referencia, a fordító a vtable-ben keresi a metódust. Ekkor hívja a ApolloSpacecraft::CollideWith(Asteroid&) metódust. Az ApolloSpacecraft::CollideWith(Asteroid&) metódusban újra referencia az inAsteroid, így az inAsteroid.CollideWith(*this) eredménye egy újabb keresés a vtable-ben. Ekkor inAsteroid referencia az ExplodingAsteroid-ra, így végül ExplodingAsteroid::CollideWith(ApolloSpacecraft&) hívódik meg.

Kettős metódus C#-ban szerkesztés

C#-ban nincs szükség látogatóra kettős metódusokhoz. Elérhető polimorfizmussal, a megfelelő argumentumot dynamicnak jelölve.[2] A futás idejű kötő kiválasztja a megfelelő túlterhelést futás időben. A döntés figyelembe veszi a példány futásidejű típusát és az argumentum futásidejű típusát.

Kettős metódus Eiffelben szerkesztés

Az Eiffelben használhatók az ágensek a kettős metódusok bevezetésére. A későbbi példa is ezt a nyelvi szerkezetet használja.

A megoldandó feladata egy rajzprogram készítése, amikkel alakzatokat (SHAPE) lehet rajzolni párhuzamosan több felületre (SURFACE). Mindkettő egyaránt ismer egy draw függvényt, de egymásról nem tudnak. Szeretnénk, ha a kettő kapcsolatba lépne egymással kovariáns módon. Egy polimorf felületet rá kell bírni arra, hogy kirajzoljon magára egy polimorf alakzatot.

Kimeneti példa szerkesztés

A kimeneti példa most szövegként adja vissza, hogy mikor melyik felületre melyik rajzelemet rajzolja ki. Az alábbi eredményekhez két SURFACE látogatót adnak át polimorf SHAPE objektumok listájának. A látogató nincs tisztában a pontos típusokkal. Ehelyett a kód futás idejű polimorfizmusra és az ágensek módszerére hagyatkozik, hogy nagy rugalmasságot érjen el a két absztrakt (deferred) osztály és leszármazottaik között.

draw a red POLYGON on ETCHASKETCH
draw a red POLYGON on GRAFFITI_WALL
draw a grey RECTANGLE on ETCHASKETCH
draw a grey RECTANGLE on GRAFFITI_WALL
draw a green QUADRILATERAL on ETCHASKETCH
draw a green QUADRILATERAL on GRAFFITI_WALL
draw a blue PARALLELOGRAM on ETCHASKETCH
draw a blue PARALLELOGRAM on GRAFFITI_WALL
draw a yellow POLYGON on ETCHASKETCH
draw a yellow POLYGON on GRAFFITI_WALL
draw a purple RECTANGLE on ETCHASKETCH
draw a purple RECTANGLE on GRAFFITI_WALL

Látogató minta szerkesztés

A látogató objektum polimorf adatszerkezetet jár be polimorf módon, és csinál valamit az egyes objektumokkal. Ez lehet függvényhívás vagy ágens használata is. Példánkban az adatszerkezet SHAPE objektumok listája, aminek elemeit egy SURFACE objektummal látogatja meg, és kirajzoltatja őket a SURFACE objektumra.

	make
			-- Print shapes on surfaces.
		local
			l_shapes: ARRAYED_LIST [SHAPE]
			l_surfaces: ARRAYED_LIST [SURFACE]
		do
			create l_shapes.make (6)
			l_shapes.extend (create {POLYGON}.make_with_color ("red"))
			l_shapes.extend (create {RECTANGLE}.make_with_color ("grey"))
			l_shapes.extend (create {QUADRILATERAL}.make_with_color ("green"))
			l_shapes.extend (create {PARALLELOGRAM}.make_with_color ("blue"))
			l_shapes.extend (create {POLYGON}.make_with_color ("yellow"))
			l_shapes.extend (create {RECTANGLE}.make_with_color ("purple"))

			create l_surfaces.make (2)
			l_surfaces.extend (create {ETCHASKETCH}.make)
			l_surfaces.extend (create {GRAFFITI_WALL}.make)

			across l_shapes as ic_shapes loop
				across l_surfaces as ic_surfaces loop
					ic_surfaces.item.drawing_agent (ic_shapes.item.drawing_data_agent)
				end
			end
		end

Az adatszerkezetek létrehozásával kezdjük. Végigiterálunk az egyik listán (SHAPE), és megengedjük, hogy a másik lista elemei sorra meglátogassák őket. A példa kódban SURFACE objektumok látogatják a SHAPE objektumokat.

A kód indirekt, a drawing_agent által polimorf módon hívja a {SURFACE}.draw metódust, és az első hívás a kettős metódusban. Átad egy indirekt és polimorf ágenst, ez a drawing_data_agent; emiatt a látogatónak elég a következőket tudnia:

  • a SURFACE kirajzolásának ágensét
  • a SHAPE rajzolási adat ágensét

Mivel a SHAPE és a SURFACE is definiálja ágenseit, a látogató kódnak nem kell tudnia, hogy mi lesz a hívás eredménye, polimorf lesz-e, vagy más. Ez az indirekció és kibontás ismeretlen a fontosabb nyelvekben, mint C, C++ és Java, habár csinálható hasonló reflexióval vagy túlterheléssel.

SURFACE szerkesztés

A {SURFACE}.draw polimorf hívásával egy ágens hívódik meg, ami a második polimorf hívás a mintában.

	deferred class
		SURFACE
	
	feature {NONE} -- Initialization
	
		make
				-- Initialize Current.
			do
				drawing_agent := agent draw
			end
	
	feature -- Access

		drawing_agent: PROCEDURE [ANY, TUPLE [STRING, STRING]]
				-- Drawing agent of Current.
	
	feature {NONE} -- Implementation
	
		draw (a_data_agent: FUNCTION [ANY, TUPLE, TUPLE [name, color: STRING]])
				-- Draw `a_shape' on Current.
			local
				l_result: TUPLE [name, color: STRING]
			do
				l_result := a_data_agent (Void)
				print ("draw a " + l_result.color + " " + l_result.name + " on " + type + "%N")
			end
	
		type: STRING
				-- Type name of Current.
			deferred end
	
	end

A 19. sor ágens argumentuma és ennek hívása a 24. sorban is polimorf. Az ágens lebont, mivel a {SURFACE}.draw semmit sem tud arról, hogy az a_data_agent melyik osztályon alapul. Így nem lehet megmondani, hogy a művelet ágense melyik osztályból való, nem kell feltétlenül a SHAPE osztály vagy leszármazottainak elemének lennie. Ez az Eiffel ágenseinek előnye a más nyelvekben használt egyszeres örökléssel, dinamikus és polimorf kötéseivel szemben.

Az ágens futás időben dinamikusan polimorf, mivel az objektum akkor jön létre, amikor létre kell jönnie, és mivel az objektummá tett rutint akkor határozza meg a környezet. Az egyedüli erős kötés tudás az ágens szignatúrájának Result típusa, ami egy két elemű TUPLE. Ez a specifikus követelmény a tartalmazó metódus (feature) kérésén alapul, ami szükséges, és nem kell elkerülni, talán nem is kerülhető el. Például a 25. sor a TUPLE elnevezett elemeit használja, hogy megfeleljen a SURFACE draw metódusának.

Jegyezzük meg, hogy csak a drawing_agent láthatósága nyilvános, azaz csak ezt exportálták ANY kliensnek! Ez azt jelenti, hogy a látogató, ami az osztály egyedüli kliense csak erről kell, hogy tudjon, hogy elvégezhesse feladatát.

SHAPE szerkesztés

A SHAPE osztály a kirajzolandó osztályok őse; tartalmazza a kirajzoláshoz szükséges adatokat. A rajzolás végezhető SURFACE objektumon, de arra nincs feltétlenül szükség. Az ágensek ismét biztosítják az indirekciót, és a nem tudást az osztályról, amire szükség van a kovariáns működéshez.

Jegyezzük meg továbbá, hogy a SHAPE osztály csak a drawing_data_agent elemet teszi nyilvánossá a kliensek számára. Így a létrehozás mellett ez az egyetlen mód, ahogy egy SHAPE objektummal kapcsolatba lehet lépni, amit bármely kliens indirekt használ, és polimorfikusan szerez adatokat a SHAPE-ről!

	deferred class
		SHAPE
	
	feature {NONE} -- Initialization
	
		make_with_color (a_color: like color)
				-- Make with `a_color' as `color'.
			do
				color := a_color
				drawing_data_agent := agent drawing_data
			ensure
				color_set: color.same_string (a_color)
			end

	feature -- Access
	
		drawing_data_agent: FUNCTION [ANY, TUPLE, like drawing_data]
				-- Data agent for drawing.
	
	feature {NONE} -- Implementation
	
		drawing_data: TUPLE [name: like name; color: like color]
				-- Data needed for drawing of Current.
			do
				Result := [name, color]
			end
	
		name: STRING
				-- Object name of Current.
			deferred end
	
		color: STRING
				-- Color of Current.

	end

Klasszikus űrhajó példa szerkesztés

A klasszikus űrhajós példa egyik változatában űrhajók, aszteroidák és űrállomások szerepelnek. Egy kettős metódus kezelheti a találkozásokat két kovariáns objektum között. Példánkban a két űrhajó USS Enterprise és USS Excelsior.

Egy kimenet:

Starship Enterprise changes position from A-001 to A-002.
Starship Enterprise takes evasive action, avoiding Asteroid `Rogue 1'!
Starship Enterprise changes position from A-002 to A-003.
Starship Enterprise takes evasive action, avoiding Asteroid `Rogue 2'!
Starship Enterprise beams a science team to Starship Excelsior as they pass!
Starship Enterprise changes position from A-003 to A-004.
Starship Excelsior changes position from A-003 to A-005.
Starship Enterprise takes evasive action, avoiding Asteroid `Rogue 3'!
Starship Excelsior is near Space Station Deep Space 9 and is dockable.
Starship Enterprise changes position from A-004 to A-005.
Starship Enterprise beams a science team to Starship Excelsior as they pass!
Starship Enterprise is near Space Station Deep Space 9 and is dockable.

Látogató szerkesztés

A látogató ebben a példában is kettős metódust valósítanak meg:

make
		-- Allow SPACESHIP objects to visit and move about in a universe.
	local
		l_universe: ARRAYED_LIST [SPACE_OBJECT]
		l_enterprise,
		l_excelsior: SPACESHIP
	do
		create l_enterprise.make_with_name ("Enterprise", "A-001")
		create l_excelsior.make_with_name ("Excelsior", "A-003")
		create l_universe.make (0)
		l_universe.force (l_enterprise)
		l_universe.force (create {ASTEROID}.make_with_name ("Rogue 1", "A-002"))
		l_universe.force (create {ASTEROID}.make_with_name ("Rogue 2", "A-003"))
		l_universe.force (l_excelsior)
		l_universe.force (create {ASTEROID}.make_with_name ("Rogue 3", "A-004"))
		l_universe.force (create {SPACESTATION}.make_with_name ("Deep Space 9", "A-005"))
		visit (l_enterprise, l_universe)
		l_enterprise.set_position ("A-002")
		visit (l_enterprise, l_universe)
		l_enterprise.set_position ("A-003")
		visit (l_enterprise, l_universe)
		l_enterprise.set_position ("A-004")
		l_excelsior.set_position ("A-005")
		visit (l_enterprise, l_universe)
		visit (l_excelsior, l_universe)
		l_enterprise.set_position ("A-005")
		visit (l_enterprise, l_universe)
	end
feature {NONE} -- Implementation
visit (a_object: SPACE_OBJECT; a_universe: ARRAYED_LIST [SPACE_OBJECT])
		-- `a_object' visits `a_universe'.
	do
		across a_universe as ic_universe loop
			check attached {SPACE_OBJECT} ic_universe.item as al_universe_object then
				a_object.encounter_agent.call ([al_universe_object.sensor_data_agent])
			end
		end
	end

A kettős metódus feloldását a 35. sorban láthatjuk, ahol két ágens indirekt működnek együtt, hogy kovariáns hívásokat hozzanak létre egymással összhangban. A visit a_objectjének van egy encounter_agentje, amit a sensor_data_agent szenzor adataival hívnak meg, melyek forrása az al_universe_object. Egy másik érdekes rész a SPACE_OBJECT osztály, és annak encounter feature-je.

Látogató akció szerkesztés

A SPACE_OBJECT példányok csak a következőket exportálják: encounter (találkozás) ágens, sensor data (szenzoradatok) ágens, és új hely beállítása. Egy űrhajó útja során objektumokat látogat meg az űrben, a szenzoradatok összegyűlnek és átadódnak a látogató objektumnak annak encounter ágensében. Így a sensor_data_agent által közvetített adatok az aktuális objektummal kapcsolatban értékelődnek ki. Ez alapján történnek meg az akciók. A többi adat privát, vagyis az export célja {NONE}, csak az adott objektumon belül használható. Az Eiffel nyelv sajátsága, hogy különböző, de ugyanolyan osztályú objektumok nem hívhatják egymás privát metódusait. Jegyezzük meg, hogy az encounter által meghívott print nem tartalmaz információt arról, hogy milyen alosztályai vannak a SPACE_OBJECT osztálynak! Itt csak az általános SPACE_OBJECT elemeit használjuk. Az a tény, hogy a kimenet értelmes, logikai tervezésen és azon alapul, amit az űrbéli objektumokról tudunk. Maga a SPACE_OBJECT nem tud semmit utódairól.

deferred class
SPACE_OBJECT
feature {NONE} -- Initialization
make_with_name (a_name: like name; a_position: like position)
    -- Initialize Current with `a_name' and `a_position'.
  do
    name := a_name
    position := a_position
    sensor_data_agent := agent sensor_data
    encounter_agent := agent encounter
  ensure
    name_set: name.same_string (a_name)
    position_set: position.same_string (a_position)
  end
feature -- Access
encounter_agent: PROCEDURE [ANY, TUPLE]
    -- Agent for managing encounters with Current.
sensor_data_agent: FUNCTION [ANY, TUPLE, attached like sensor_data_anchor]
    -- Agent for returning sensor data of Current.
feature -- Settings
set_position (a_position: like position)
    -- Set `position' with `a_position'.
  do
    print (type + " " + name + " changes position from " + position + " to " + a_position + ".%N")
    position := a_position
  ensure
    position_set: position.same_string (a_position)
  end
feature {NONE} -- Implementation
encounter (a_sensor_agent: FUNCTION [ANY, TUPLE, attached like sensor_data_anchor])
    -- Detect and report on collision status of Current with `a_radar_agent'.
  do
    a_sensor_agent.call ([Void])
    check attached {like sensor_data_anchor} a_sensor_agent.last_result as al_sensor_data then
      if not name.same_string (al_sensor_data.name) then
        if (position.same_string (al_sensor_data.position)) then
          if ((al_sensor_data.is_dockable and is_dockable) and
              (is_manned and al_sensor_data.is_manned) and
              (is_manueverable and al_sensor_data.is_not_manueverable)) then
            print (type + " " + name + " is near " + al_sensor_data.type + " " +
                al_sensor_data.name + " and is dockable.%N")
          elseif ((is_dockable and al_sensor_data.is_dockable) and
                (is_manned and al_sensor_data.is_manned) and
                (is_manueverable and al_sensor_data.is_manueverable)) then
            print (type + " " + name + " beams a science team to " + al_sensor_data.type + " " +
                al_sensor_data.name + " as they pass!%N")
          elseif (is_manned and al_sensor_data.is_not_manned) then
            print (type + " " + name + " takes evasive action, avoiding " +
                al_sensor_data.type + " `" + al_sensor_data.name + "'!%N")
          end
        end
      end
    end
  end
name: STRING
    -- Name of Current.
type: STRING
    -- Type of Current.
  deferred
  end
position: STRING
    -- Position of Current.
is_dockable: BOOLEAN
    -- Is Current dockable with another manned object?
  deferred
  end
is_manned: BOOLEAN
    -- Is Current a manned object?
  deferred
  end
is_manueverable: BOOLEAN
    -- Is Current capable of being moved?
  deferred
  end
sensor_data: attached like sensor_data_anchor
    -- Sensor data of Current.
  do
      Result := [name, type, position, is_dockable, not is_dockable, is_manned, not is_manned, is_manueverable, not is_manueverable]
    end

  sensor_data_anchor: detachable TUPLE [name, type, position: STRING; is_dockable, is_not_dockable, is_manned, is_not_manned, is_manueverable, is_not_manueverable: BOOLEAN]
      -- Sensor data type anchor of Current.

end

Jelenleg három leszármazottja van a SPACE_OBJECT osztálynak:

SPACE_OBJECT
ASTEROID
SPACESHIP
SPACESTATION

Példánkban az ASTEROID aszteroidát, a SPACESHIP űrhajót, és a SPACESTATION a Deep Space Nine űrállomást jelenti. Mindegyik bizonyos tulajdonságokat és a type feature-t állítja be. A name a konstruktor (creation) és a position számára szükséges.

class
SPACESHIP
inherit
SPACE_OBJECT
create
make_with_name
feature {NONE} -- Implementation
type: STRING = "Starship"
  -- <Precursor>
is_dockable: BOOLEAN = True
  -- <Precursor>
is_manned: BOOLEAN = True
  -- <Precursor>
is_manueverable: BOOLEAN = True
  -- <Precursor>
end

Tehát egy SPACESHIP objektumnak van személyzete, manőverezhető és dokkolható. Ezzel szemben egy aszteroidának nincsenek ilyen tulajdonságai. Egy SPACESTATION objektumnak van személyzete és dokkolható, de nem manőverezhető. Az egymás közelében levő objektumok tulajdonságaik szerint kapcsolatba lépnek egymással. A név azonosítja a példányokat, tehát az ugyanolyan nevű és típusú példányok kölcsönhatását a rendszer megakadályozza.

Eiffel összefoglaló szerkesztés

Az Eiffel ágensei lehetővé teszik, hogy egy lépéssel jobban el lehessen távolítani az objektumokat egymástól. A rutinokat az osztályból kiemelve ágenssé alakítjuk, és ahelyett, hogy közvetlenül az objektumokat hívogatnánk. Az ágensek bírnak szignatúrával és lehet, hogy visszatérési értékkel is, amivel ideális alanyai a statikus típusellenőrzésnek, anélkül, hogy felfednék az objektumok specifikus részleteit. Ugyanakkor teljes joggal polimorfak, így csak az eredmény kód bír azzal a tudással, ami a munka elvégzéséhez szükséges. Másrészt az objektumok részleteinek elrejtése a többi kovariáns objektum elől a karbantartást is támogatja. Mindezt biztosítják az ágensek. Velük bonyolultabb helyzetek is megoldhatók, lásd multimetódus.

Az ágensek használatának hátránya, hogy lassabban hívhatók, mint a normál tagfüggvények; úgyhogy ha valamit el lehet végezni azokkal is, akkor nem kell az ágenseket bevetni. Ha azonban lényegi változások várhatók a felhasznált osztályokban, akkor mégis szükség van ágensekre a karbantarthatóság érdekében.

Jegyzetek szerkesztés

  1. More Effective C++ by Scott Meyers(Addison-Wesley, 1996)
  2. Using Type dynamic (C# Programming Guide). Microsoft Developer Network . Microsoft, 2009. szeptember 30. (Hozzáférés: 2016. május 25.) „... Overload resolution occurs at run time instead of at compile time if one or more of the arguments in a method call have the type dynamic ...”

Fordítás szerkesztés

Ez a szócikk részben vagy egészben a Double dispatch 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.