Delegation | |
---|---|
delegation | |
Beskrivs i Design Patterns | Inte |
Delegering är ett grundläggande designmönster där ett objekt externt uttrycker något beteende , men i själva verket överför ansvaret för att utföra detta beteende till ett relaterat objekt. Delegeringsmönstret är den grundläggande abstraktionen på vilken de andra mönstren - sammansättning (även kallad aggregering), mixins och aspekter - implementeras .
Möjligheten att ändra beteendet hos en viss instans av ett objekt istället för att skapa en ny klass genom arv.
Detta mönster gör det i allmänhet svårt att optimera för hastighet till förmån för förbättrad abstraktionsrenhet.
Även om delegering inte stöds av Java-språket, stöds det av många utvecklingsmiljöer [1] .
I det här Java - exemplet Bhar klassen en stubmetod som skickar metoder till . Klassen låtsas ha klassattribut . foo()bar()ABA
Källtext i java klass A { void foo () { System . ut . println ( "A: metod foo() anropad" ); } void bar () { System . ut . println ( "A: metodbar() anropad" ); } } klass B { // Skapa ett objekt vars metoder kommer att delegera beteende. A a = nytt A (); void foo () { a . foo (); } void bar () { a . bar (); } } public class Main { public static void main ( String [] args ) { B b = new B (); b . foo (); b . bar (); } } Komplext exempelMed hjälp av gränssnitt kan delegering göras på ett mer flexibelt och typsäkert sätt. I det här exemplet kan klassen Cdelegera till Aantingen B. Klassen Char metoder för att växla mellan klasser Aoch B. Att inkludera redskapsförlängningen förbättrar typsäkerheten eftersom varje klass måste implementera metoderna i gränssnittet. Den största nackdelen är mer kod.
Låt oss ta ett exempel. Anta att du behöver implementera en timer på ett sådant sätt att någon funktion anropas efter en viss tid. Timerprogrammeraren vill ge en funktionstilldelning till användarna i sin klass (andra programmerare).
Källtext i java /** * Gränssnittet beskriver åtgärden som kommer att anropas när * timerhändelsen inträffar. */ interface TimerAction { void onTime (); } class WakeUpAction implementerar TimerAction { @Override public void onTime () { System . ut . println ( "Dags att gå upp!" ); } } class ChickenIsReadyAction implementerar TimerAction { @Override public void onTime () { System . ut . println ( "Kycklingen är klar!" ); } } /** * Timerklass. Under vissa förhållanden anropas TimerAction. */ class Timer { TimerAction action ; /** * En funktion som programmeraren anropar för att ställa in tiden. */ void run () { if ( isTime ()) { action . onTime (); } } /** * Någon funktion som tar hand om allt tidsarbete. Dess * genomförande är inte intressant i detta sammanhang. * * @return */ private boolean isTime () { return true ; } public static void main ( String [] args ) { System . ut . println ( "Ange åtgärdstyp:" ); Scanner scanner = ny skanner ( System . in ); String actionType = skanner . nästa rad (); Timer timer = ny Timer (); if ( actionType . equalsIgnoreCase ( "ställ in väckningstimer" )) { timer . action = new WakeUpAction (); } else if ( actionType . equalsIgnoreCase ( "ställ kycklingtimer" )) { timer . action = new ChickenIsReadyAction (); } timer . köra (); }Det här exemplet är en C++- version av det komplexa Java-exemplet ovan. Eftersom C++ inte har en gränssnittskonstruktion spelar den helt abstrakta klassen samma roll . För- och nackdelarna är i princip desamma som i Java-exemplet.
Källtext i c++ #include <iostream> klass I { offentliga : virtuellt tomrum f () = 0 ; virtuellt tomrum g () = 0 ; }; klass A : offentlig I { offentliga : void f () { std :: cout << "A: anropsmetod f()" << std :: endl ; } void g () { std :: cout << "A: anropsmetod g()" << std :: endl ; } }; klass B : offentlig I { offentliga : void f () { std :: cout << "B: anropsmetod f()" << std :: endl ; } void g () { std :: cout << "B: anropsmetod g()" << std :: endl ; } }; klass C : public I { offentliga : // Konstruktör C () : m_i ( nytt A () ) { } // Destructor virtual ~ C () { ta bort m_i ; } void f () { m_i -> f (); } void g () { m_i -> g (); } // Med dessa metoder ändrar vi fältobjektet, vars metoder vi kommer att delegera void till A () { ta bort m_i ; m_i = newA ( ); } void toB () { ta bort m_i ; m_i = nytt B (); } privat : // Vi deklarerar ett objekt vars metoder vi kommer att delegera I * m_i ; }; int main () { Cc ; _ c . f (); c . g (); c . toB (); c . f (); c . g (); returnera 0 ; } /* Utdata: A: anropa f()-metoden A: anropa g() -metoden B: anropa f()-metoden B: anropa g()-metoden */Detta är ett exempel på ett fall som ofta uppstår i praktiken. Det finns en uppgift att skapa en klass för lagring av listan över anställda. Varje anställds data lagras i ett objekt av klassen Employee. Det finns en färdig och standardklass för att lagra en lista med Employee-objekt. Den har redan implementerat mekanismer för att arbeta med listan (till exempel minnesallokering, lägga till och ta bort från listan). Att ärva personallistklassen från objektlistklassen är inte acceptabelt här, eftersom vi kommer att få alla metoder (även de som vi inte är intresserade av). Dessutom kommer vi att behöva utföra typgjutning i vissa fall. Den mest eleganta vägen ut ur det här fallet är att delegera några av metoderna för objektlistklassen till klassen medarbetarlista. I OOP-regler är det bäst att representera listan över objekt med en privat (privat) metod för listan över anställda. I det här fallet kan listan nås via en indexerare.
Källtext i C# använder System ; använder System.Collections.Generic ; använder System.Linq ; använder System.Text ; namnområde Anställda { /// <sammanfattning> /// Klass för att lagra anställds data. /// </summary> class Employee { private string name ; privat stråkavdelning ; _ public Employee ( strängnamn , strängavdelning ) { detta . _ _ namn = namn ; detta . avdelning = avdelning ; } /// <sammanfattning> /// Anställds namn. /// </summary> offentlig sträng Namn { get { returnera detta . namn ; } } /// <sammanfattning> /// Arbetsavdelning. /// </summary> public string Department { get { return this . avdelning ; } } } /// <sammanfattning> /// Klass för att lagra en lista över anställda. /// </summary> class EmployeesList { privat lista < Anställd > anställda = ny lista < Anställd >(); /// <sammanfattning> /// Egenskap för att få och skriva en anställd efter index. /// </summary> /// <param name="index">Anställd index.</param> /// <returns>Anställd.</returns> offentlig Anställd detta [ int index ] { get { return anställda [ index ]; } set { anställda [ index ] = värde ; } } /// <sammanfattning> /// Lägga till en ny anställd. /// </summary> /// <param name="employee">Ny anställd.</param> public void Lägg till ( Anställd anställd ) { anställda . Lägg till ( anställd ); } /// <sammanfattning> /// Ta bort en befintlig anställd. /// </summary> /// <param name="employee">Den anställde som ska tas bort.</param> public void Ta bort ( Anställd anställd ) { anställda . Ta bort ( anställd ); } /// <sammanfattning> /// Sök efter en anställd efter namn. /// </summary> /// <param name="name">Anställds namn.</param> /// <param name="offset">Position att börja söka från.</param> // / < returns>Anställd index.</returns> public int GetIndexOfEmployeeByName ( strängnamn , int offset = 0 ) { for ( int i = offset ; i < anställda . Antal ; i ++) { if ( anställda [ i ] . Namn == namn ) { return i ; } } return - 1 ; } } class Program { static void Main ( string [] args ) { //Skapa en lista över anställda och lägg till poster till den EmployeesList empList = new EmployeesList (); empList . Lägg till ( ny anställd ( "Shlensky Dmitry" , "webstudio" )); empList . Lägg till ( ny anställd ( "Kusy Nazar" , "webstudio" )); empList . Lägg till ( ny anställd ( "Magpie Orest" , "webstudio" )); //Sök efter anställd Kusyi Nazar och visa resultatet när du söker från början och från konsolen på andra plats . WriteLine ( empList . GetIndexOfEmployeeByName ( "Kusy Nazar" ). ToString ()); Konsol . WriteLine ( empList . GetIndexOfEmployeeByName ( "Kusy Nazar" , 2 ). ToString ()); //Sök och ta bort medarbetare Soroka Orestes empList . Remove ( empList [ empList . GetIndexOfEmployeeByName ( "Magpie Orestes" )]); } } } Källtext i C# 2 använder System ; använder System.Collections.Generic ; använder System.Linq ; använder System.Text ; namnområde Anställda { /// <sammanfattning> /// Klass för att lagra anställds data. /// </summary> class Employee { private string name ; privat stråkavdelning ; _ public Employee ( strängnamn , strängavdelning ) { detta . _ _ namn = namn ; detta . avdelning = avdelning ; } /// <sammanfattning> /// Anställds namn. /// </summary> offentlig sträng Namn { get { returnera detta . namn ; } } /// <sammanfattning> /// Arbetsavdelning. /// </summary> public string Department { get { return this . avdelning ; } } } /// <sammanfattning> /// Klass för att lagra en lista över anställda. /// </summary> class EmployeesList { privat lista < Anställd > anställda = ny lista < Anställd >(); /// <sammanfattning> /// Egenskap för att få och skriva en anställd efter index. /// </summary> /// <param name="index">Anställd index.</param> /// <returns>Anställd.</returns> offentlig Anställd detta [ int index ] { get { return anställda [ index ]; } set { anställda [ index ] = värde ; } } /// <sammanfattning> /// Egenskap för att få och skriva en anställd vid namn. /// </summary> /// <param name="name">Anställds namn.</param> /// <returns>Den första anställde vars namn matchade eller null</returns> offentligt Anställd denna [ strängnamn ] { get { foreach ( Anställd artikel i anställda ) { if ( artikel . Namn == namn ) returnera föremål ; } returnera null ; } } /// <sammanfattning> /// Lägga till en ny anställd. /// </summary> /// <param name="employee">Ny anställd.</param> public void Lägg till ( Anställd anställd ) { anställda . Lägg till ( anställd ); } /// <sammanfattning> /// Ta bort en befintlig anställd. /// </summary> /// <param name="employee">Den anställde som ska tas bort.</param> public void Ta bort ( Anställd anställd ) { anställda . Ta bort ( anställd ); } /// <sammanfattning> /// Sök efter en anställd efter namn. /// </summary> /// <param name="name">Anställds namn.</param> /// <param name="offset">Position att börja söka från.</param> // / < returns>Anställd index.</returns > public int GetIndexOfEmployeeByName ( strängnamn , int offset ) { int index = - 1 ; for ( int i = offset ; i < anställda . Antal ; i ++) { if ( anställda [ i ]. Namn == namn ) { index = i ; bryta ; } } returnera index ; } /// <sammanfattning> /// Sök efter en anställd efter namn. /// </summary> /// <param name="name">Anställds namn.</param> /// <returns>Anställd index.</returns> public int GetIndexOfEmployeeByName ( strängnamn ) { return GetIndexOfEmployeeByName ( namn 0 ) ; } } class Program { static void Main ( string [] args ) { //Skapa en lista över anställda och lägg till poster till den EmployeesList empList = new EmployeesList (); empList . Lägg till ( ny anställd ( "Shlensky Dmitry" , "webstudio" )); empList . Lägg till ( ny anställd ( "Kusy Nazar" , "webstudio" )); empList . Lägg till ( ny anställd ( "Magpie Orest" , "webstudio" )); //Sök efter anställd Kusyi Nazar och visa resultatet när du söker från början och från konsolen på andra plats . WriteLine ( empList . GetIndexOfEmployeeByName ( "Kusy Nazar" ). ToString ()); Konsol . WriteLine ( empList . GetIndexOfEmployeeByName ( "Kusy Nazar" , 2 ). ToString ()); //Sök och ta bort medarbetare Soroka Orestes empList . Remove ( empList [ "Magpie Orestes" ]); } } }Det här exemplet är en Object Pascal -version av det icke-triviala exemplet ovan.
Källtext i Object Pascal enhet EnhetArbetsgivare ; gränssnitt använder Contnrs ; typ // Klass för att lagra anställds data TEmployee = klass privat FName : string ; FDepartament : string ; public constructor Skapa ( namn , avdelning : sträng ) ; publicerad egenskap Namn : sträng läst FName ; egenskap Departament : sträng läst FDepartament ; slut ; // Klass för lagring av listan över anställda TEmployeersList = klass privat // Objekt i klassen "lista över objekt" FEmployeersList : TObjectList ; funktion GetEmployee ( Index : Heltal ) : TEmployee ; procedure SetEmployee ( Index : Heltal ; const Value : TEmployee ) ; offentlig konstruktör Skapa ; förstörare Destroy ; åsidosätta ; function Add ( Anställd : TEmployee ) : Heltal ; procedur Ta bort ( Anställd : TEmployee ) ; function IndexEmployeeByName ( Namn : sträng ; Offset : Heltal = 0 ) : Heltal ; egenskap Anställda [ Index : Heltal ] : TEmployee läs GetEmployee skriv SetEmployee ; standard ; slut ; genomförande {anställd} konstruktör TE-anställd . Skapa ( Namn , Avdelning : sträng ) ; börja FName := Namn ; FDepartament := Avdelning ; slut ; { Temployeers List } konstruktör TEmployeersList . skapa ; begin // Skapa ett objekt vars metoder vi kommer att delegera FEmployeersList := TObjectList . skapa ; slut ; destructor TEmployeersList . Förstöra ; starta FEemployersList . Gratis ; ärvt ; slut ; funktion Temployeers List . GetEmployee ( Index : Heltal ) : TEmployee ; börja Resultat := FEmployeersList [ Index ] som TEmployee ; slut ; procedur TEmployeersList . SetEmployee ( Index : Heltal ; const Value : TEmployee ) ; börja FEmployeersList [ Index ] := Värde ; slut ; funktion Temployeers List . IndexEmployeeByName ( Namn : sträng ; Offset : Heltal = 0 ) : Heltal ; // Sekventiell sökning efter en anställd med namn // Genom argumentet Offset kan du ange från vilken position du ska söka. // Om medarbetaren inte hittas kommer den att returnera ett värde mindre än noll (-1) var Index : Integer ; börja Resultat := - 1 ; // Förutsatt att det inte finns i listan för Index := FEmployeersList . Räkna - 1 ned till Offset gör om ( FEmployeersList [ Index ] som TEmployee ) . Namn = Namn börjar sedan Resultat := Index ; avsluta ; slut ; slut ; funktion Temployeers List . Lägg till ( Anställd : TEmployee ) : Heltal ; börja Resultat := FEemployeers List . Lägg till ( anställd ) ; slut ; procedur TEmployeersList . Ta bort ( Anställd : TEmployee ) ; starta FEemployersList . Ta bort ( anställd ) ; slut ; slut .Tyvärr använder inte alla programmerare delegeringsmönstret. Till exempel ärvde Borland (utvecklaren av programmeringsmiljön Delphi ) i sitt standardklassbibliotek den tidigare nämnda TObjectList-objektlistklassen från TList - pekarlistklassen . Detta orsakade missnöje bland några erfarna programmerare.
Det här exemplet är en PHP- version av det enkla Java- exemplet ovan.
PHP5 källkod <?php klass A { public function f () { print "A: Anropa metoden f()<br />" ; } public function g () { print "A: Vi kallar metoden g()<br />" ; } } klass C { privat $_a ; offentlig funktion __construct () { $this -> _a = nytt A ; } public function f () { $this -> _a -> f (); } public function g () { $this -> _a -> g (); } public function y () { print "C: call method y()<br />" ; } } $obj = nytt C ; $obj -> f (); $obj -> g (); $obj -> y (); ?> Komplext exempelDet här exemplet är en PHP- version av det komplexa Java- exemplet ovan.
PHP5 källkod <?php // använd gränssnitt för typ säkerhetsgränssnitt I { public function f ( ); offentlig funktion g (); } klass A implementerar I { public function f () { print "A: Call f()<br />" ; } public function g () { print "A: Vi kallar metoden g()<br />" ; } } klass B implementerar I { public function f () { print "B: Call f()<br />" ; } public function g () { print "B: Call method g()<br />" ; } } klass C implementerar I { privat $_i ; // skapa ett objekt vars metoder kommer att delegeras offentlig funktion __construct () { $this -> _i = new A ; } // med dessa metoder ändrar vi fältobjektet, vars metoder vi kommer att delegera offentlig funktion till A () { $this -> _i = new A ; } public function toB () { $this -> _i = new B ; } // delegerade metoder public function f () { $this -> _i -> f (); } public function g () { $this -> _i -> g (); } } $obj = nytt C ; $obj -> f (); $obj -> g (); $obj -> toB (); $obj -> f (); $obj -> g (); ?> Icke-trivialt exempelDet här exemplet är en PHP -version av det icke-triviala exemplet ovan.
PHP5 källkod <?php // klass för lagring av anställd data klass Anställd { privat $_name ; privat $_department ; public function __construct ( $name , $departament ) { $this -> _name = $name ; $this -> _departament = $departament ; } public function getName () { return $this -> _name ; } public function getDepartament () { return $this -> _departament ; } } // klass för att lagra en lista med objekt klass ObjectList { privat $_objList ; public function __construct () { $this -> free (); } /** *för att inte bli uttråkad! */ 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 funktionsuppsättning ( $index , $obj ) { $ this -> _objList [ $index ] = $obj ; } } // klass för lagring av anställda klass EmployeeList { // objekt av klassen "lista över objekt" privat $_employeersList ; public function __construct (){ // skapa ett objekt vars metoder vi kommer att delegera $this -> _employeersList = new ObjectList ; } public function getEmployer ( $index ) { return $this -> _employeersList -> get ( $index ); } public function setEmployer ( $index , Employee $objEmployer ) { $this -> _employeersList -> set ( $index , $objEmployer ); } public function __destruct () { $this -> _employeersList -> free (); } public function add ( Anställd $objEmployer ) { $this -> _employeersList -> add ( $objEmployer ); } public function remove ( Employee $objEmployer ) { $this -> _employeersList -> remove ( $objEmployer ); } // sekventiell sökning efter en anställd med namn // genom argumentet $offset kan du ställa in från vilken position du ska söka. // om medarbetaren inte hittas kommer den att returnera ett värde mindre än noll (-1) public function getIndexByName ( $name , $offset = 0 ) { $result = - 1 ; // antar att det inte finns i listan $cnt = $this -> _employeersList -> count (); for ( $i = $offset ; $i < $cnt ; $i ++ ) { if ( ! strcmp ( $name , $this -> _employeersList -> get ( $i ) -> getName () ) ) { $result = $i ; bryta ; } } returnera $result ; } } $obj1 = ny anställd ( "Tanasiychuk Stepan" , "webstudio" ); $obj2 = ny anställd ( "Kusy Nazar" , "webstudio" ); $obj3 = ny anställd ( "Magpie Orest" , "webstudio" ); $objList = new EmployeeList (); $objList -> lägg till ( $obj1 ); $objList -> add ( $obj2 ); $objList -> lägg till ( $obj3 ); echo "<pre>" ; print_r ( $objList ); echo "<hr>" ; $index = $objList -> getIndexByName ( "Kusy Nazar" ); $obj4 = $objList -> getEmployer ( $index ); print_r ( $obj4 ); echo "<hr>" ; $objList -> setEmployer ( 2 , $obj4 ); print_r ( $objList ); echo "</pre>" ; ?>Källkod i Python
#coding: utf-8 #python 3 klass A : def f ( self ): print ( 'A : calling method f' ) def g ( self ): print ( 'A : calling method g' ) class C : def __init__ ( själv ): själv . A = A () def f ( själv ): returnera själv . A. _ f () def g ( själv ): returnera själv . A. _ g () c = C () c . f () #A: anropsmetod f c . g () #A: anropsmetod gDesign mönster | |
---|---|
Main | |
Generativ | |
Strukturell | |
Beteende | |
Parallell programmering |
|
arkitektonisk |
|
Java EE-mallar | |
Andra mallar | |
Böcker | |
Personligheter |