Delegation | |
---|---|
delegation | |
Beskrevet i Design Patterns | Ikke |
Delegering er et grundlæggende designmønster, hvor et objekt eksternt udtrykker en vis adfærd , men i virkeligheden overfører ansvaret for at udføre denne adfærd til et relateret objekt. Delegationsmønsteret er den grundlæggende abstraktion , hvorpå de andre mønstre - sammensætning (også kaldet aggregering), mixins og aspekter - er implementeret .
Evnen til at ændre adfærden for en bestemt forekomst af et objekt i stedet for at skabe en ny klasse gennem arv.
Dette mønster gør det generelt vanskeligt at optimere for hastighed til fordel for forbedret abstraktionsrenhed.
Selvom delegering ikke understøttes af Java-sproget, understøttes det af mange udviklingsmiljøer [1] .
I dette Java - eksempel Bhar klassen en stubmetode , der sender metoder til . Klassen foregiver at have klasseattributter . foo()bar()ABA
Kildetekst i java klasse A { void foo () { System . ud . println ( "A: metode foo() kaldet" ); } void bar () { System . ud . println ( "A: metode bar() kaldet" ); } } klasse B { // Opret et objekt, hvis metoder vil uddelegere adfærd. A a = nyt A (); void foo () { en . foo (); } void bar () { a . bar (); } } public class Main { public static void main ( String [] args ) { B b = new B (); b . foo (); b . bar (); } } Kompleks eksempelVed at bruge grænseflader kan delegering ske på en mere fleksibel og typesikker måde. I dette eksempel kan klassen Cuddelegere til Aenten B. Klassen Char metoder til at skifte mellem klasser Aog B. Inkludering af redskabsudvidelsen forbedrer typesikkerheden, fordi hver klasse skal implementere metoderne i grænsefladen. Den største ulempe er mere kode.
Lad os tage et eksempel. Antag, at du skal implementere en timer på en sådan måde, at en funktion kaldes efter et vist tidsrum. Timer-programmøren ønsker at give en funktionstildeling til brugerne af sin klasse (andre programmører).
Kildetekst i java /** * Grænsefladen beskriver den handling, der vil blive kaldt, når * timerhændelsen indtræffer. */ interface TimerAction { void onTime (); } klasse WakeUpAction implementerer TimerAction { @Override public void onTime () { System . ud . println ( "Tid til at stå op!" ); } } class ChickenIsReadyAction implementerer TimerAction { @Override public void onTime () { System . ud . println ( "Kyllingen er klar!" ); } } /** * Timer klasse. Under visse forhold kaldes TimerAction. */ class Timer { TimerAction handling ; /** * En funktion, som programmøren kalder for at indstille tiden. */ void run () { if ( isTime ()) { handling . OnTime (); } } /** * Nogen funktion, der tager sig af hele tiden arbejde. Dens * implementering er ikke interessant i denne sammenhæng. * * @return */ private boolean isTime () { return true ; } public static void main ( String [] args ) { System . ud . println ( "Indtast handlingstype:" ); Scanner scanner = ny Scanner ( System . in ); String actionType = scanner . næste linje (); Timer timer = ny Timer (); if ( actionType . equalsIgnoreCase ( "indstil wake up timer" )) { timer . action = ny WakeUpAction (); } else if ( actionType . equalsIgnoreCase ( "indstil kyllingetimeren" )) { timer . action = new ChickenIsReadyAction (); } timer . køre (); }Dette eksempel er en C++- version af det komplekse Java-eksempel ovenfor. Da C++ ikke har en grænsefladekonstruktion, spiller den fuldt abstrakte klasse den samme rolle . Fordelene og ulemperne er grundlæggende de samme som i Java-eksemplet.
Kildetekst i c++ #include <iostream> klasse I { offentligt : virtuelt tomrum f () = 0 ; virtuelt tomrum g () = 0 ; }; klasse A : offentlig I { offentligt : void f () { std :: cout << "A: kalder metode f()" << std :: endl ; } void g () { std :: cout << "A: kaldemetode g()" << std :: endl ; } }; klasse B : offentlig I { offentligt : void f () { std :: cout << "B: kaldemetode f()" << std :: endl ; } void g () { std :: cout << "B: kaldemetode g()" << std :: endl ; } }; klasse C : offentlig I { offentligt : // Konstruktør C () : m_i ( ny A () ) { } // Destructor virtual ~ C () { slet m_i ; } void f () { m_i -> f (); } void g () { m_i -> g (); } // Med disse metoder ændrer vi feltobjektet , hvis metoder vi uddelegerer void til A () { slet m_i ; m_i = newA ( ); } void toB () { slet m_i ; m_i = nyt B (); } privat : // Vi erklærer et objekt, hvis metoder vi vil uddelegere I * m_i ; }; int main () { Cc ; _ c . f (); c . g (); c . toB (); c . f (); c . g (); returnere 0 ; } /* Output: A: kald f()-metoden A: kald g()- metoden B: kald f()-metoden B: kald g()-metoden */Dette er et eksempel på en sag, man ofte støder på i praksis. Der er en opgave at oprette en klasse til opbevaring af listen over medarbejdere. Hver medarbejders data gemmes i et objekt af klassen Medarbejder. Der er en færdiglavet og standardklasse til lagring af en liste over medarbejderobjekter. Den har allerede implementeret mekanismer til at arbejde med listen (for eksempel hukommelsesallokering, tilføjelse og fjernelse fra listen). At arve medarbejderlisteklassen fra objektlisteklassen er ikke acceptabel her, fordi vi får alle metoderne (også dem, vi ikke er interesserede i). Derudover vil vi i nogle tilfælde skulle udføre typestøbning. Den mest elegante vej ud af denne sag er at uddelegere nogle af metoderne i objektlisteklassen til medarbejderlisteklassen. I OOP-regler er det bedst at repræsentere listen over objekter med en privat (privat) metode af listen over medarbejdere. I dette tilfælde kan listen tilgås via en indeksering.
Kildetekst i C# bruger System ; ved hjælp af System.Collections.Generic ; ved hjælp af System.Linq ; ved hjælp af System.Text ; navneområde Medarbejdere { /// <resumé> /// Klasse til lagring af medarbejderdata. /// </summary> class Employee { private string name ; privat strengeafdeling ; _ offentlig Medarbejder ( strengnavn , strengafdeling ) { dette . _ _ navn = navn ; dette . afdeling = afdeling ; } /// <resumé> /// Medarbejdernavn. /// </summary> offentlig streng Navn { get { return this . navn ; } } /// <resumé> /// Arbejdsafdeling. /// </summary> public string Department { get { return this . afdeling ; } } } /// <resumé> /// Klasse til lagring af en liste over medarbejdere. /// </summary> class EmployeesList { private List < Employee > employee = new List < Employee >(); /// <resumé> /// Ejendom til at få og skrive en medarbejder efter indeks. /// </summary> /// <param name="index">Medarbejderindeks.</param> /// <returns>Medarbejder.</returns> public Employee this [ int index ] { get { return medarbejdere [ indeks ]; } sæt { medarbejdere [ indeks ] = værdi ; } } /// <resumé> /// Tilføjelse af en ny medarbejder. /// </summary> /// <param name="employee">Ny medarbejder.</param> public void Tilføj ( Medarbejder medarbejder ) { medarbejdere . Tilføj ( medarbejder ); } /// <resumé> /// Sletning af en eksisterende medarbejder. /// </summary> /// <param name="employee">Medarbejderen, der skal fjernes.</param> public void Fjern ( Medarbejder medarbejder ) { ansatte . Fjern ( medarbejder ); } /// <resumé> /// Sekventiel søgning efter en medarbejder ved navn. /// </summary> /// <param name="name">Medarbejdernavn.</param> /// <param name="offset">Position at begynde at søge fra.</param> // / < returns>Medarbejderindeks.</returns> public int GetIndexOfEmployeeByName ( strengnavn , int offset = 0 ) { for ( int i = offset ; i < ansatte . Antal ; i ++ ) { if ( ansatte [ i ] . Navn == navn ) { return i ; } } retur - 1 ; } } klasse Program { static void Main ( string [] args ) { //Opret en liste over medarbejdere og tilføj poster til den EmployeesList empList = new EmployeesList (); empList . Tilføj ( ny medarbejder ( "Shlensky Dmitry" , "webstudie " )); empList . Tilføj ( ny medarbejder ( "Kusy Nazar" , "webstudie " )); empList . Tilføj ( ny medarbejder ( "Magpie Orest" , "webstudie" )); //Søg efter medarbejder Kusyi Nazar og vis resultatet, når du søger fra begyndelsen og fra 2. positionskonsollen . WriteLine ( empList . GetIndexOfEmployeeByName ( "Kusy Nazar" ). ToString ()); Konsol . WriteLine ( empList . GetIndexOfEmployeeByName ( "Kusy Nazar" , 2 ). ToString ()); //Søg og slet medarbejder Soroka Orestes empList . Fjern ( empList [ empList . GetIndexOfEmployeeByName ( "Magpie Orestes" )]); } } } Kildetekst i C# 2 bruger System ; ved hjælp af System.Collections.Generic ; ved hjælp af System.Linq ; ved hjælp af System.Text ; navneområde Medarbejdere { /// <resumé> /// Klasse til lagring af medarbejderdata. /// </summary> class Employee { private string name ; privat strengeafdeling ; _ offentlig Medarbejder ( strengnavn , strengafdeling ) { dette . _ _ navn = navn ; dette . afdeling = afdeling ; } /// <resumé> /// Medarbejdernavn. /// </summary> offentlig streng Navn { get { return this . navn ; } } /// <resumé> /// Arbejdsafdeling. /// </summary> public string Department { get { return this . afdeling ; } } } /// <resumé> /// Klasse til lagring af en liste over medarbejdere. /// </summary> class EmployeesList { private List < Employee > employee = new List < Employee >(); /// <resumé> /// Ejendom til at få og skrive en medarbejder efter indeks. /// </summary> /// <param name="index">Medarbejderindeks.</param> /// <returns>Medarbejder.</returns> public Employee this [ int index ] { get { return medarbejdere [ indeks ]; } sæt { medarbejdere [ indeks ] = værdi ; } } /// <resumé> /// Ejendom til at få og skrive en medarbejder ved navn. /// </summary> /// <param name="name">Medarbejdernavn.</param> /// <returns>Den første medarbejder, hvis navn matchede eller null</returns> offentlige Medarbejder denne [ strengnavn ] { get { foreach ( Medarbejder vare i medarbejdere ) { if ( item . Navn == navn ) returnere vare ; } returner null ; } } /// <resumé> /// Tilføjelse af en ny medarbejder. /// </summary> /// <param name="employee">Ny medarbejder.</param> public void Tilføj ( Medarbejder medarbejder ) { medarbejdere . Tilføj ( medarbejder ); } /// <resumé> /// Sletning af en eksisterende medarbejder. /// </summary> /// <param name="employee">Medarbejderen, der skal fjernes.</param> public void Fjern ( Medarbejder medarbejder ) { ansatte . Fjern ( medarbejder ); } /// <resumé> /// Sekventiel søgning efter en medarbejder ved navn. /// </summary> /// <param name="name">Medarbejdernavn.</param> /// <param name="offset">Position at begynde at søge fra.</param> // / < returns>Medarbejderindeks.</returns> public int GetIndexOfEmployeeByName ( string name , int offset ) { int index = - 1 ; for ( int i = offset ; i < ansatte . Antal ; i ++) { if ( ansatte [ i ]. Navn == navn ) { index = i ; bryde ; } } returner indeks ; } /// <resumé> /// Sekventiel søgning efter en medarbejder ved navn. /// </summary> /// <param name ="name">Medarbejdernavn.</param> /// <returns>Medarbejderindeks.</returns> public int GetIndexOfEmployeeByName ( strengnavn ) { return GetIndexOfEmployeeByName ( navn 0 ) ; } } klasse Program { static void Main ( string [] args ) { //Opret en liste over medarbejdere og tilføj poster til den EmployeesList empList = new EmployeesList (); empList . Tilføj ( ny medarbejder ( "Shlensky Dmitry" , "webstudie " )); empList . Tilføj ( ny medarbejder ( "Kusy Nazar" , "webstudie " )); empList . Tilføj ( ny medarbejder ( "Magpie Orest" , "webstudie" )); //Søg efter medarbejder Kusyi Nazar og vis resultatet, når du søger fra begyndelsen og fra 2. positionskonsollen . WriteLine ( empList . GetIndexOfEmployeeByName ( "Kusy Nazar" ). ToString ()); Konsol . WriteLine ( empList . GetIndexOfEmployeeByName ( "Kusy Nazar" , 2 ). ToString ()); //Søg og slet medarbejder Soroka Orestes empList . Remove ( empList [ "Magpie Orestes" ]); } } }Dette eksempel er en Object Pascal -version af det ikke-trivielle eksempel ovenfor.
Kildetekst i Object Pascal enhed UnitEmployers ; interface bruger Contnrs ; type // Klasse til lagring af medarbejderdata TEmployee = klasse privat FName : string ; FAfdeling : streng ; offentlig konstruktør Opret ( navn , afdeling : streng ) ; publiceret egenskab Navn : streng læst FName ; egenskab Departament : streng læst FDepartament ; ende ; // Klasse til lagring af listen over medarbejdere TEmployeersList = klasse privat // Objekt af "list of objects" -klassen FEmployeersList : TObjectList ; funktion GetEmployee ( Indeks : Heltal ) : TEmployee ; procedure SetEmployee ( Indeks : Heltal ; const Værdi : TEmployee ) ; offentlig konstruktør Opret ; destructor Destroy ; tilsidesætte ; funktion Tilføj ( Medarbejder : TEmployee ) : Heltal ; procedure Fjern ( medarbejder : TEmployee ) ; function IndexEmployeeByName ( Navn : streng ; Offset : Heltal = 0 ) : Heltal ; ejendom Medarbejdere [ Indeks : Heltal ] : TEmployee læser GetEmployee skriv SetEmployee ; standard ; ende ; implementering {medarbejder} konstruktør TE-medarbejder . Opret ( navn , afdeling : streng ) ; start FName := Navn ; FDepartament := Afdeling ; ende ; { Temployeers List } konstruktør TEmployeersList . skabe ; start // Opret et objekt, hvis metoder vi vil uddelegere FEmployeersList := TObjectList . skabe ; ende ; destructor TEmployeersList . Ødelæg ; start FEemployersList . Gratis ; nedarvet ; ende ; funktion Vikarliste . GetEmployee ( indeks : heltal ) : TEmployee ; start Resultat := FEmployeersList [ Indeks ] som TEmployee ; ende ; procedure TEmployeersList . SetEmployee ( Indeks : Heltal ; const Værdi : TEmployee ) ; start FEmployeersList [ Indeks ] := Værdi ; ende ; funktion Vikarliste . IndexEmployeeByName ( Navn : streng ; Offset : Heltal = 0 ) : Heltal ; // Sekventiel søgning efter en medarbejder ved navn // Gennem argumentet Offset kan du indstille den position, hvorfra der skal søges. // Hvis medarbejderen ikke findes, vil den returnere en værdi mindre end nul (-1) var Index : Integer ; begynde Resultat := - 1 ; // Forudsat at det ikke er på listen for Index := FEmployeersList . Tæl 1 ned til Offset gør hvis ( FEmployeersList [ Indeks ] som TEmployee ) . Navn = Navn og derefter begynde Resultat := Indeks ; udgang ; ende ; ende ; funktion Vikarliste . Tilføj ( medarbejder : TEmployee ) : Heltal ; start Resultat := FEemployeersList . Tilføj ( medarbejder ) ; ende ; procedure TEmployeersList . Fjern ( medarbejder : TEmployee ) ; start FEemployersList . Fjern ( medarbejder ) ; ende ; ende .Desværre er det ikke alle programmører, der bruger delegationsmønsteret. For eksempel arvede Borland (udvikleren af Delphi - programmeringsmiljøet ) i dets standardklassebibliotek den førnævnte TObjectList-objektlisteklasse fra TList - markørlisteklassen . Dette forårsagede utilfredshed blandt nogle erfarne programmører.
Dette eksempel er en PHP- version af det simple Java- eksempel ovenfor.
PHP5 kildekode <?php klasse A { public function f () { print "A: Kald metoden f()<br />" ; } public function g () { print "A: Vi kalder metoden g()<br />" ; } } klasse C { privat $_a ; offentlig funktion __construct () { $this -> _a = nyt A ; } offentlig funktion f () { $this -> _a -> f (); } offentlig funktion g () { $this -> _a -> g (); } public function y () { print "C: kalde metode y()<br />" ; } } $obj = nyt C ; $obj -> f (); $obj -> g (); $obj -> y (); ?> Kompleks eksempelDette eksempel er en PHP- version af det komplekse Java- eksempel ovenfor.
PHP5 kildekode <?php // brug grænseflade til type sikkerhedsgrænseflade I { offentlig funktion f ( ); offentlig funktion g (); } klasse A implementerer I { public function f () { print "A: Kald f()<br />" ; } public function g () { print "A: Vi kalder metoden g()<br />" ; } } klasse B implementerer I { public function f () { print "B: Kald f()<br />" ; } public function g () { print "B: Kaldmetode g()<br />" ; } } klasse C implementerer I { private $_i ; // opret et objekt, hvis metoder vil blive uddelegeret offentlig funktion __construct () { $this -> _i = new A ; } // med disse metoder ændrer vi feltobjektet , hvis metoder vi vil delegere offentlig funktion til A () { $this -> _i = new A ; } public function toB () { $this -> _i = new B ; } // delegerede metoder offentlig funktion f () { $this -> _i -> f (); } offentlig funktion g () { $this -> _i -> g (); } } $obj = nyt C ; $obj -> f (); $obj -> g (); $obj -> toB (); $obj -> f (); $obj -> g (); ?> Ikke-trivielt eksempelDette eksempel er en PHP -version af det ikke-trivielle eksempel ovenfor.
PHP5 kildekode <?php // klasse til lagring af medarbejderdata klasse Medarbejder { privat $_name ; privat $_afdeling ; offentlig funktion __construct ( $navn , $afdeling ) { $this -> _name = $navn ; $this -> _departament = $departament ; } public function getName () { return $this -> _name ; } public function getDepartament () { return $this -> _departament ; } } // klasse til lagring af en liste over objekter klasse ObjectList { privat $_objList ; public function __construct () { $this -> free (); } /** *ikke at kede sig! */ public function free () { $this -> _objList = array (); } public function count () { return count ( $this -> _objList ); } public function add ( $obj ) { array_push ( $this -> _objList , $obj ); } public function remove ( $obj ) { $k = array_search ( $obj , $this -> _objList , true ); if ( $k !== false ) { unset ( $this -> _objList [ $k ] ); } } public function get ( $index ) { return $this -> _objList [ $index ]; } offentlig funktionssæt ( $index , $obj ) { $ this - > _objList [ $index ] = $obj ; } } // klasse til opbevaring af medarbejdere klasse EmployeeList { // objekt i klassen "liste over objekter" privat $_employeersList ; public function __construct (){ // opret et objekt, hvis metoder vi vil uddelegere $this -> _employeersList = new ObjectList ; } public function getEmployer ( $index ) { return $this -> _employeersList -> get ( $index ); } public function setEmployer ( $index , Employee $objEmployer ) { $this -> _employeersList -> set ( $index , $objEmployer ); } offentlig funktion __destruct () { $this -> _employeersList -> gratis (); } public function add ( Medarbejder $objEmployer ) { $this -> _employeersList -> add ( $objEmployer ); } public function remove ( Medarbejder $objEmployer ) { $this -> _employeersList -> remove ( $objEmployer ); } // sekventiel søgning efter en medarbejder ved navn // gennem $offset-argumentet kan du indstille den position, hvorfra der skal søges. // hvis medarbejderen ikke findes, vil den returnere en værdi mindre end nul (-1) public function getIndexByName ( $navn , $offset = 0 ) { $result = - 1 ; // antag at det ikke er på listen $cnt = $this -> _employeersList -> count (); for ( $i = $offset ; $i < $cnt ; $i ++ ) { if ( ! strcmp ( $navn , $this -> _employeersList -> get ( $i ) -> getName () ) ) { $result = $i ; bryde ; } } returner $resultat ; } } $obj1 = ny medarbejder ( "Tanasiychuk Stepan" , "webstudie " ); $obj2 = ny medarbejder ( "Kusy Nazar" , "webstudie " ); $obj3 = ny medarbejder ( "Magpie Orest" , "webstudie" ); $objList = ny medarbejderliste (); $objList -> tilføje ( $obj1 ); $objList -> tilføje ( $obj2 ); $objList -> tilføje ( $obj3 ); echo "<præ>" ; print_r ( $objList ); echo "<hr>" ; $index = $objList -> getIndexByName ( "Kusy Nazar" ); $obj4 = $objList -> getEmployer ( $indeks ); print_r ( $obj4 ); echo "<hr>" ; $objList -> setEmployer ( 2 , $obj4 ); print_r ( $objList ); echo "</pre>" ; ?>Kildekode i Python
#coding: utf-8 #python 3 klasse A : def f ( self ): print ( 'A : kalder metode f' ) def g ( self ): print ( 'A : kalder metode g' ) klasse C : def __init__ ( selv ): selv . A = A () def f ( selv ): returnere selv . A. _ f () def g ( selv ): returnere selv . A. _ g () c = C () c . f () #A: kaldemetode f c . g () #A: kaldemetode gDesign mønstre | |
---|---|
Hoved | |
Generativ | |
Strukturel | |
Adfærdsmæssigt | |
Parallel programmering |
|
arkitektonisk |
|
Java EE skabeloner | |
Andre skabeloner | |
Bøger | |
Personligheder |