Látogató (tervminta)

Az oldal jelenlegi verzióját még nem ellenőrizték tapasztalt közreműködők, és jelentősen eltérhet a 2016. január 4-én felülvizsgált verziótól ; az ellenőrzések 26 szerkesztést igényelnek .
Látogató
Látogató
Típusú viselkedési
Célja a fő osztály megváltoztatása nélkül adjon hozzá új műveleteket.
Szerkezet
esetekben érvényes amikor több osztályhoz hasonló (ugyanolyan) műveletet kell végrehajtani.
profik
  • új funkciókat adnak egyszerre több osztályhoz anélkül, hogy megváltoztatnák ezen osztályok kódját ;
  • lehetővé teszi, hogy információt szerezzen az objektum típusáról;
  • kettős ütemezés;
  • lehetőség saját algoritmus leírására minden objektumtípushoz .
Mínuszok
  • a kiszolgált osztály megváltoztatásakor módosítania kell a sablonkódot;
  • nehéz új osztályokat felvenni, mert frissíteni kell a látogató és fiai hierarchiáját.
Leírása: Tervezési minták Igen

A  látogató egy viselkedési tervezési minta , amely leír egy műveletet, amelyet más osztályok objektumain hajtanak végre. Amikor látogatót vált, nincs szükség a kiszolgált osztályok megváltoztatására .

A sablon bemutatja az elveszett típusú információk visszaállításának klasszikus módszerét anélkül, hogy kétszeres lefelé küldést kellene igénybe venni.

Probléma megoldva

El kell végeznie néhány leválasztott műveletet számos objektumon, de el kell kerülnie a kódjuk szennyezését. És nincs mód vagy vágy arra, hogy lekérdezzük az egyes csomópontok típusát, és a mutatót a megfelelő típusra irányítsuk a kívánt művelet végrehajtása előtt.

Kihívás

Valamely struktúra minden objektumán egy vagy több műveletet hajtanak végre. Új műveletet kell meghatároznia az objektumosztályok megváltoztatása nélkül.

Megoldás

A függetlenség érdekében a látogatónak külön hierarchiája van. A struktúráknak van egy bizonyos interakciós felülete.

Használat

Ha van esély arra, hogy a kiszolgált osztályhierarchia megváltozik, vagy instabil lesz, vagy a nyilvános felület elég hatékony ahhoz, hogy a sablon hozzáférjen, akkor annak használata rosszindulatú.

Egy alaposztály jön létre Visitormetódusokkal visit()a szülő minden alosztályához Element. Adjon hozzá egy metódust accept(visitor)az elemhierarchiához. Minden objektumon végrehajtandó művelethez Elementszármaztassa az Visitorosztályt a következőből. A metódusmegvalósításoknak visit()az osztály nyilvános felületét kell használniuk Element. Ennek eredményeként: a kliensek objektumokat hoznak létre, és a hívással Visitortovábbítják őket minden objektumnak . Elementaccept()

Ajánlások

A sablont akkor kell használni, ha:

Előnyök és hátrányok

Előnyök :

Hátrányok :

Megvalósítás

  1. Adjon hozzá egy metódust accept(Visitor)az "elem" hierarchiához.
  2. Hozzon létre egy alaposztályt Visitor, és határozzon meg metódusokat visit()minden elemtípushoz.
  3. Hozzon létre származtatott osztályokat Visitorminden egyes elemekkel végzett művelethez.
  4. A kliens létrehoz egy objektumot Visitor, és átadja a hívott metódusnakaccept().

C++

Megvalósítási példa C++ nyelven #include <iostream> #include <karakterlánc> osztály Foo ; osztály Bár ; osztály Bas ; osztály látogató { nyilvános : virtuális érvénytelen látogatás ( Foo & ref ) = 0 ; virtuális érvénytelen látogatás ( Bar & ref ) = 0 ; virtuális érvénytelen látogatás ( Baz & ref ) = 0 ; virtuális ~ Látogató () = alapértelmezett ; }; class elem { nyilvános : virtuális üresedés elfogadása ( Látogató & v ) = 0 ; virtuális ~ Elem () = alapértelmezett ; }; osztály Foo : nyilvános elem { nyilvános : void elfogad ( Látogató és v ) felülbírálás { v . látogatás ( * ez ); } }; class Bar : public Element { nyilvános : void elfogad ( Látogató és v ) felülbírálás { v . látogatás ( * ez ); } }; class Baz : public Element { nyilvános : void elfogad ( Látogató és v ) felülbírálás { v . látogatás ( * ez ); } }; osztály GetType : nyilvános látogató { nyilvános : std :: karakterláncérték ; _ nyilvános : void visit ( Foo & ref ) override { érték = "foo" ; } void visit ( Bar & ref ) override { érték = "sáv" ; } void visit ( Baz & ref ) override { érték = "alap" ; } }; int main () { Foo foo ; Bár bár ; baz baz ; Element * elements [] = { & foo , & bar , & baz }; for ( auto elem : elements ) { GetType látogató ; elem -> elfogad ( látogató ); std :: cout << látogató . érték << std :: endl ; } return 0 ; }

Java

Java megvalósítási példa public class Demo { public static void main ( String [] args ) { Point p = new Point2d ( 1 , 2 ); Látogató v = új Csebisev (); o . elfogad ( v ); Rendszer . ki . println ( p . getMetric ( ) ); } } interface Látogató { public void látogatás ( Pont2d p ); nyilvános üres látogatás ( Pont3d p ); } abstract class Pont { public abstract void elfogad ( Vistor v ); privát kettős metrika = - 1 ; public double getMetric () { return metrika ; } public void setMetric ( kettős metrika ) { this . metrika = metrika ; } } osztály Pont2d kiterjeszti a pontot { public Pont2d ( double x , double y ) { this . x = x ; ezt . y = y_ _ } public void elfogad ( Vistor v ) { v . látogatás ( ez ); } privát double x ; public double getX () { return x ; } magán dupla y ; public double getY () { return y ; } } osztály Pont3d kiterjeszti a pontot { public Point3d ( double x , double y , double z ) { this . x = x ; ezt . y = y_ _ ezt . z = z _ } public void elfogad ( Vistor v ) { v . látogatás ( ez ); } privát double x ; public double getX () { return x ; } magán dupla y ; public double getY () { return y ; } privát kettős z ; public double getZ () { return z ; } } class Euclid implements Visitor { public void visit ( Point2d p ) { p . setMetric ( Math . sqrt ( p . getX () * p . getX () + p . getY () * p . getY () ) ); } nyilvános érvénytelen látogatás ( pont3d p ) { p . setMetric ( Math . sqrt ( p . getX () * p . getX () + p . getY () * p . getY () + p . getZ () * p . getZ () ) ); } } class Csebisev implementálja a Látogató { public void látogatás ( Pont2d p ) { double ax = Math . abs ( p.getX ( ) ) ; double -ay = Math . abs ( p . getY () ); o . setMetric ( ax > ay ? ax : ay ); } public void látogatás ( Pont3d p ) { double ax = Math . abs ( p.getX ( ) ) ; double -ay = Math . abs ( p . getY () ); double az = Math . absz ( p . getZ () ); double max = ax > ay ? ax : igen ; if ( max < az ) max = az ; o . setMetric ( max ); } }

C#

Megvalósítási példa C# nyelven public static class Demo { private static void () { Pont p = new Pont2D ( 1 , 2 ); IVisitor v = új Csebisev (); o . elfogad ( v ); Konzol . WriteLine ( p . Metric ); } } belső interfész IVisitor { void Látogatás ( Pont2D p ); érvénytelen látogatás ( Point3Dp ) ; } belső absztrakt osztály Pont { public double Metric { get ; készlet ; } = -1 ; _ public abstract void Elfogadás ( IVisitor látogató ); } belső osztály Pont2D : Pont { public Pont2D ( double x , double y ) { X = x ; Y = y_ _ } public double X { get ; } public double Y { get ; } public override void Elfogadás ( IVisitor visitor ) { látogató . látogatás ( ez ); } } belső osztály Pont3D : Pont { public Point3D ( double x , double y , double z ) { X = x ; Y = y_ _ Z = z _ } public double X { get ; } public double Y { get ; } public double Z { get ; } public override void Elfogadás ( IVisitor visitor ) { látogató . látogatás ( ez ); } } belső osztály Euklidész : IVisitor { public void Látogatás ( Pont2D p ) { p . Metrika = Math . Sqrt ( p . X * p . X + p . Y * p . Y ); } public void Látogatás ( Point3D p ) { p . Metrika = Math . Sqrt ( p . X * p . X + p . Y * p . Y + p . Z * p . Z ); } } belső osztály Csebisev : IVisitor { public void Látogatás ( Pont2D p ) { var ax = Math . abs ( X o . ); varay = matematika _ _ Abs ( p . Y ); o . Metrikus = ax > ay ? ax : igen ; } public void Látogatás ( Pont3D p ) { var ax = Math . abs ( X o . ); varay = matematika _ _ Abs ( p . Y ); var az = Math . Abs ( Z o . ); varmax = ax > ay ? _ ax : igen ; if ( max < az ) max = az ; o . Metrika = max ; } }

PHP

Példa megvalósításra php -ben <?php interface Látogató { public function látogatás ( Pont $pont ); } abstract class Pont { public abstract function accept ( Látogató $látogató ); privát $_metrika = - 1 ; public function getMetric () { return $this -> _metric ; } public function setMetric ( $metrika ) { $this -> _metric = $metrika ; } } osztály Pont2d kiterjeszti a { pontot public function __construct ( $x , $y ) { $this -> _x = $x ; $this -> _y = $y ; } public function accept ( Látogató $látogató ) { $látogató -> látogatás ( $this ); } privát $_x ; public function getX () { return $this -> _x ; } privát $_y ; public function getY () { return $this -> _y ; } } class Point3d kiterjeszti a pontot { public function __construct ( $x , $y , $z ) { $this -> _x = $x ; $this -> _y = $y ; $ez -> _z = $z ; } public function accept ( Látogató $látogató ) { $látogató -> látogatás ( $this ); } privát $_x ; public function getX () { return $this -> _x ; } privát $_y ; public function getY () { return $this -> _y ; } privát $_z ; public function getZ () { return $this -> _z ; } } class Euclid implements Visitor { public function látogatás ( $p pont ) { if ( $p instanceof Point2d ) $p -> setMetric ( sqrt ( $p -> getX () * $p -> getX () + $p -> getY () * $p -> getY () ) ); elseif ( $p instanceof Point3d ) $p -> setMetric ( sqrt ( $p -> getX () * $p -> getX () + $p -> getY () * $p -> getY () + $p - > getZ () * $p -> getZ () ) ); } } class Chebisev implements Visitor { public function látogatás ( $p pont ) { if ( $p instanceof Point2d ){ $ax = abs ( $p -> getX () ); $ay = abs ( $p -> getY () ); $p -> setMetric ( $ax > $ay ? $ax : $ay ); } elseif ( $p instanceof Point3d ){ $ax = abs ( $p -> getX () ); $ay = abs ( $p -> getY () ); $az = abs ( $p -> getZ () ); $max = $ax > $ay ? $ax : $ay ; if ( $max < $az ) $max = $az ; $p -> setMetric ( $max ); } } } függvény kezdete (){ $p = new Pont2d ( 1 , 2 ); $v = új Csebisev ( ); $p -> elfogad ( $v ); echo ( $p -> getMetric () ); }; start ();

Python

Megvalósítási példa Pythonban abc importból ABCMeta , abstractmethod gépelésből import List _ _ osztály kém ( metaclass = ABCMeta ): """ Kémlátogató """ @abstractmethod def visit_military_base ( self , military_base : 'MilitaryBase' ) -> Nincs : """ A haditengerészet katonai bázisának felkeresése "" " belépő @abstractmethod def visit_headquarters ( self , headquarters : 'Headquarters' ) -> None : """ Látogassa meg a hadsereg főhadiszállását """ igazolvány osztály MilitaryFacility ( metaclass = ABCMeta ): """ Katonai létesítmény - meglátogatott létesítmény """ @abstractmethod def accept ( self , spy : Spy ) -> None : """ Kémlátogató elfogadása """ pass osztályú katonai bázis ( MilitaryFacility ): """ Tengeralattjáró katonai bázis """ def __init__ ( self ) -> None : self . _secret_draftings = 1 én . _nukleáris_tengeralattjárók = 1 def __repr__ ( self ) -> str : return 'A katonai bázisnak {} nukleáris tengeralattjárója és {} titkos tervrajza van' . formátum ( saját . _nukleáris_tengeralattjárók , saját . _titkos_rajzok ) def accept ( self , spy : Spy ) -> None : spy . látogatás_katonai_bázis ( saját ) def remove_secret_draftings ( self ) -> None : if self . _secret_draftings : saját . _titkos_rajzok -= 1 def remove_nuclear_submarine ( self ) -> None : if self . _nukleáris_tengeralattjárók : saját . _nukleáris_tengeralattjárók -= 1 @property def is_combat_ready ( self ) -> bool : önmagát adja vissza . _nukleáris_tengeralattjárók > 0 osztályú parancsnokság ( MilitaryFacility ): """ Hadsereg parancsnoksága """ def __init__ ( self ) -> None : self . _generals = 3 én . _secret_documents = 2 def __repr__ ( self ) -> str : return 'A főhadiszálláson {} tábornok és {} titkos dokumentum van ' . formátum ( self . _generals , self . _secret_documents ) def accept ( self , spy : Spy ) -> None : spy . visit_headquarters ( saját ) def remove_general ( self ) -> None : if self . _generálisok : én . _tábornokok -= 1 def remove_secret_documents ( self ) -> None : if self . _secret_documents : saját . _titkos_dokumentumok -= 1 @property def is_command_ready ( self ) -> bool : önmagát adja vissza . _generals > 0 osztály ScoutSpy ( Spy ): """ Scout (konkrét kém) """ def __init__ ( self ): self . _collected_info = {} # Itt már ismerjük a konkrét objektumtípust def visit_military_base ( self , military_base : MilitaryBase ) -> None : self . _collected_info [ 'base' ] = 'Katonai bázis: \n\t {} \n\t Kész: {} ' . formátum ( str ( katonai_bázis ), 'Igen' , ha katonai_bázis . is_combat_ready else 'Nem' ) def visit_headquarters ( self , headquarters : Headquarters ) -> None : self . _collected_info [ 'headquarters' ] = 'Székhely: \n\t {} \n\t Parancs: {} ' . formátum ( str ( headquarters ), 'Futó' , ha headquarters . is_command_ready else 'Nem működik' ) def report ( self ) -> str : return 'Információ a felderítőtől: \n {} \n ' . format ( ' \n ' . join ( self . _collected_info . Values ​​​​()) ) osztály JamesBond ( Kém ): """ James Bond (egy másik konkrét kém) """ def visit_military_base ( saját , katonai_bázis : MilitaryBase ) -> Nincs : # James Bond meglátogatja a katonai bázist katonai_bázis . remove_secret_draftings () # ellopja a katonai_bázis titkos rajzait . remove_nuclear_submarine () # és végül felrobbant egy nukleáris tengeralattjárót def visit_headquarters ( self , headquarters : Headquarters ) -> None : # James Bond meglátogatja a központot . remove_general () # ... főhadiszállás . remove_general () # ... főhadiszállás . remove_secret_documents () # ... főhadiszállás . remove_general () # Megsemmisíti az összes tábornokot egymás után headquarters . remove_secret_documents () # és ellopja az összes titkos dokumentumot if __name__ == '__main__' : bázis = Katonai Bázis () hq = Főhadiszállás () # Nem számít, melyik katonai létesítmény létesítményei = [ alap , hq ] # típusa: Lista[Katonai létesítmény] scout = ScoutSpy () print ( 'Sending a Scout... \n ' ) for f in létesítmények : f . elfogad ( cserkész ) nyomtatás ( scout.report ( ) ) print ( 'Sending Bond on a mission... \n ' ) spy = JamesBond () f - re a létesítményekben : f . elfogad ( kém ) print ( 'Felderítő küldése az adatok frissítésére... \n ' ) for f in létesítményekben : f . elfogad ( cserkész ) nyomtatás ( scout.report ( ) ) """ KIMENET: Felderítőt küldeni... Információk a felderítőtől: Központi parancsnokság: A parancsnokságon 3 tábornok és 2 titkos dokumentum található Parancsnokság: Működő Katonai bázis: A katonai bázison 1 db atomtengeralattjáró és 1 db titkos rajz található Harckészültség: Igen Bond küldetése... Felderítő küldése az adatok frissítésére... Információ a felderítőtől: Központi parancsnokság: 0 tábornok és 0 titkos dokumentum van a parancsnokságon Parancsnokság: Nem működik Katonai bázis: 0 atomtengeralattjáró és 0 titkos rajz található a katonai bázison Felkészültség: Nincs """

Delphi

Megvalósítási példa Delphiben program Demo ; típus Point2D = osztály ; Point3D = osztály ; IVisitor = interfész eljárás Visit ( p : Point2D ) ; túlterhelés ; eljárás Látogatás ( p : Point3D ) ; túlterhelés ; vége ; Pont = privát osztály FMetric : Double ; köztulajdon Metric : Dupla olvasás FMetric FMetric írás ; _ eljárás Elfogadás ( látogató : IVisitor ) ; virtuális ; absztrakt ; vége ; Pont2D = osztály ( Pont ) privát FX : Double ; FY : Dupla ; köztulajdon X : Dupla olvasás FX ; _ Y tulajdonság : Dupla olvasás FY ; konstruktor Létrehozás ( const x , y : Double ) ; eljárás Elfogadás ( Látogató : IVisitor ) ; felülbírálni ; vége ; Point3D = osztály ( Pont ) privát FX : Double ; FY : Dupla ; FZ : Dupla ; köztulajdon X : Dupla olvasás FX ; _ Y tulajdonság : Dupla olvasás FY ; tulajdonság Z : Dupla olvasás FZ ; konstruktor Létrehozás ( const x , y , z : Double ) ; eljárás Elfogadás ( Látogató : IVisitor ) ; felülbírálni ; vége ; Euklid = osztály ( TInterfacedObject , IVisitor ) nyilvános eljárás Látogatás ( p : Point2D ) ; túlterhelés ; eljárás Látogatás ( p : Point3D ) ; túlterhelés ; vége ; Chebisev = osztály ( TInterfacedObject , IVisitor ) nyilvános eljárás Látogatás ( p : Point2D ) ; túlterhelés ; eljárás Látogatás ( p : Point3D ) ; túlterhelés ; vége ; {Point2D} eljárás Pont2D . Elfogadás ( Látogató : IVisitor ) ; Kezdje Látogató . Látogatás ( Self ) ; vége ; konstruktor Point2D . Létrehozás ( const x , y : Double ) ; kezdődik FX := x ; FY := y ; vége ; {Point3D} eljárás Point3D . Elfogadás ( Látogató : IVisitor ) ; kezdődik Látogató . Látogatás ( Self ) ; vége ; konstruktor Point3D . Létrehozása ( const x , y , z : Double ) ; kezdődik FX := x ; FY := y ; FX := z ; vége ; { Euklidész } eljárás Eulid . Látogatás ( p : Point2D ) ; kezdődik p . Metrika := Sqrt ( Sqr ( p . X ) + Sqr ( p . Y )) ; vége ; eljárás Eulid . Látogatás ( p : Point3D ) ; kezdődik p . Metrikus := Sqrt ( Sqr ( p . X ) + Sqr ( p . Y ) + Sqr ( p . Z )) ; vége ; {Csebisev} eljárás Csebisev . Látogatás ( p : Point2D ) ; var ax , ay : Kettős ; begin ax := Abs ( p . X ) ; ay := Abs ( p . Y ) ; if ax > ay then p . Metrikus := ax else p . Metrikus : = igen vége ; eljárás Csebisev . Látogatás ( p : Point3D ) ; var ax , ay , az , max : Double ; begin ax := Abs ( p . X ) ; ay := Abs ( p . Y ) ; az := Abs ( p . Z ) ; if ax > ay akkor max := ax else max := ay ; if max < az then max := az ; o . Metrika := max ; vége ; varp : pont ; _ v : IVVisitor ; kezdődik p := Pont2D . Létrehoz ( 1 , 2 ) ; v := Csebisev . létrehozni ; o . elfogadja ( v ) ; WriteLn ( p . Metric : 0 : 2 ) ; v := Eulid . létrehozni ; o . elfogadja ( v ) ; WriteLn ( p . Metric : 0 : 2 ) ; o . Ingyenes ; Readln ; // várja meg, amíg megnyomja az Entert end .

Swift

Megvalósítási példa Swiftben protokoll WarehouseItem { var name : String { get set } var isBroken : Bool { get set } var price : Int { get set } } class WarehouseItemImpl : WarehouseItem { var név : String = "" var isBroken : Bool = false var price : Int = 0 init ( név : String , isBroken : Bool , ár : Int ) { self . név = név én . isBroken = isBroken self . ár = ár } } protokoll Warehouse { var items : [ WarehouseItem ] { get set } func addItem ( item : WarehouseItem ) func accept ( látogató : BasicVisitor ) } class WarehouseImpl : Raktár { var items : [ WarehouseItem ] = [] func addItem ( cikk : WarehouseItem ) { tételek . hozzáfűzés ( elem ) } func accept ( visitor : BasicVisitor ) { for item in items { visitor . látogatás ( elem AnyObject néven ) } } } protokoll BasicVisitor { func visit ( _ anObject : AnyObject ) } class QualityCheckerVisitor : BasicVisitor { func visit ( _ anObject : AnyObject ) { if let obj = anObject as ? Raktárcikk { if obj . isBroken { print ( "is törött igaz" ) } else { print ( "tört hamis" ) } if let _ = anObject as ? Raktár { nyomtatás ( "Jó raktár " ) } } } class PriceCheckerVisitor : BasicVisitor { func visit ( _ anObject : AnyObject ) { if let obj = anObject as ? WarehouseItem { print ( " \( obj . name ) | Ár: \( obj . price ) rub." ) } if let _ = anObject as ? Raktár { nyomtatás ( " Nincs költség" ) } } // A Visitor használata let raktár = WarehouseImpl () raktár . addItem ( cikk : WarehouseItemImpl ( név : "Tétel 1" , isBroken : true , ár : 100 )) raktár . addItem ( cikk : WarehouseItemImpl ( név : "Tétel 2" , isBroken : false , ár : 300 )) raktár . addItem ( cikk : WarehouseItemImpl ( név : " 3. cikk " , törött : false , ár : 500 )) let price = PriceCheckerVisitor () let qulity = QualityCheckerVisitor () raktár . elfogad ( látogató : ár ) raktár . elfogad ( látogató : qulity )

Irodalom

  • E. Gamma, R. Helm, R. Johnson, J. Vlissides . Objektumorientált tervezés technikái. Tervezési minták. - Szentpétervár. : Péter, 2001. - 368 p. — ISBN 5-272-00355-1 .

Linkek