Valtuuskunta | |
---|---|
valtuuskunta | |
Kuvattu suunnittelukuvioissa | Ei |
Delegointi on perussuunnittelumalli , jossa objekti ilmaisee ulkoisesti jonkinlaista käyttäytymistä , mutta todellisuudessa siirtää vastuun tämän käyttäytymisen suorittamisesta siihen liittyvälle objektille . Delegointimalli on perustavanlaatuinen abstraktio , jonka pohjalta muut mallit - koostumus (kutsutaan myös aggregaatioksi), sekoitukset ja aspektit - toteutetaan .
Mahdollisuus muuttaa objektin tietyn ilmentymän käyttäytymistä sen sijaan, että luotaisiin uusi luokka perinnön kautta.
Tämä malli tekee yleensä nopeuden optimoinnin vaikeaksi paremman abstraktion puhtauden hyväksi.
Vaikka Java-kieli ei tue delegointia, monet kehitysympäristöt tukevat sitä [1] .
Tässä Java - esimerkissä luokassa Bon tynkämenetelmä , joka välittää menetelmät . Luokka teeskentelee omaavansa luokkaattribuutteja . foo()bar()ABA
Lähdeteksti javassa luokka A { void foo () { Järjestelmä . ulos . println ( "A: menetelmä foo() kutsutaan" ); } void bar () { Järjestelmä . ulos . println ( "A: method bar() kutsutaan" ); } } luokka B { // Luo objekti, jonka menetelmät delegoivat käyttäytymistä. A a = uusi A (); void foo () { a . foo (); } void bar () { a . baari (); } } public class Main { public static void main ( String [] args ) { B b = new B (); b . foo (); b . baari (); } } Monimutkainen esimerkkiKäyttöliittymien avulla delegointi voidaan tehdä joustavammin ja tyyppiturvallisemmin . Tässä esimerkissä luokka Cvoi delegoida Ajoko B. Luokassa Con menetelmiä vaihtaa luokkien välillä Aja B. Laitelaajennuksen sisällyttäminen parantaa tyyppiturvallisuutta, koska jokaisen luokan tulee toteuttaa menetelmät rajapinnassa. Suurin haittapuoli on enemmän koodia.
Otetaan esimerkki. Oletetaan, että sinun täytyy toteuttaa ajastin siten, että jokin toiminto kutsutaan tietyn ajan kuluttua. Ajastinohjelmoija haluaa antaa toimintomäärityksen luokkansa käyttäjille (muille ohjelmoijille).
Lähdeteksti javassa /** * Käyttöliittymä kuvaa toiminnon, jota kutsutaan, kun * ajastintapahtuma tapahtuu. */ käyttöliittymä TimerAction { void onTime (); } class WakeUpAction toteuttaa TimerActionin { @Override public void onTime () { Järjestelmä . ulos . println ( "Aika nousta ylös!" ); } } class ChickenIsReadyAction toteuttaa TimerActionin { @Override public void onTime () { System . ulos . println ( "Kana on valmis!" ); } } /** * Ajastinluokka. Tietyissä olosuhteissa TimerAction kutsutaan. */ class Ajastin { TimerAction action ; /** * Toiminto, jota ohjelmoija kutsuu asettaakseen ajan. */ void run () { if ( isTime ()) { action . ajoissa (); } } /** * Jokin toiminto, joka huolehtii koko ajan työstä. Sen * toteutus ei ole kiinnostava tässä yhteydessä. * * @return */ yksityinen boolean isTime () { return true ; } public static void main ( String [ ] args ) { Järjestelmä . ulos . println ( "Anna toimintotyyppi:" ); Skanneriskanneri = uusi Skanneri ( System . in ) ; Merkkijono actionType = skanneri . nextLine (); Ajastinajastin = uusi Ajastin ( ); if ( actionType . equalsIgnoreCase ( "set wake up timer" )) { ajastin . toiminta = uusi WakeUpAction (); } else if ( actionType . equalsIgnoreCase ( "aseta kanaajastin" )) { ajastin . toiminta = uusi ChickenIsReadyAction (); } ajastin . juosta (); }Tämä esimerkki on C++- versio yllä olevasta monimutkaisesta Java-esimerkistä. Koska C++:lla ei ole rajapintarakennetta, täysin abstraktilla luokalla on sama rooli . Edut ja haitat ovat periaatteessa samat kuin Java-esimerkissä.
Lähdeteksti c++:ssa #include <iostream> luokka I { julkinen : virtuaalinen tyhjä f () = 0 ; virtuaalinen tyhjä g () = 0 ; }; luokka A : julkinen I { julkinen : void f () { std :: cout << "A: kutsumenetelmä f()" << std :: endl ; } void g () { std :: cout << "A: kutsu menetelmä g()" << std :: endl ; } }; luokka B : julkinen I { julkinen : void f () { std :: cout << "B: kutsu menetelmä f()" << std :: endl ; } void g () { std :: cout << "B: kutsu menetelmä g()" << std :: endl ; } }; luokka C : julkinen I { julkinen : // Konstruktori C () : m_i ( uusi A () ) { } // Tuhoaja virtuaalinen ~ C () { poista m_i ; } void f () { m_i -> f (); } void g () { m_i -> g (); } // Näillä menetelmillä muutamme kenttäobjektin, jonka menetelmät delegoimme void toA:lle () { poista m_i ; m_i = uusiA ( ); } void toB () { poista m_i ; m_i = uusi B (); } yksityinen : // Ilmoitamme objektin, jonka menetelmät delegoimme I * m_i ; }; int main () { Cc ; _ c . f (); c . g (); c . toB (); c . f (); c . g (); paluu 0 ; } /* Tulos: A: kutsu f()-metodia A: kutsu g() -metodia B: kutsu f()-metodia B: kutsu g()-metodia */Tämä on esimerkki tapauksesta, jota käytännössä kohdataan usein. Tehtävänä on luoda luokka työntekijäluettelon tallentamista varten. Jokaisen työntekijän tiedot tallennetaan Työntekijä-luokan objektiin. Työntekijä-objektien luettelon tallentamiseen on valmis ja vakioluokka. Se on jo ottanut käyttöön mekanismeja luettelon kanssa työskentelyä varten (esimerkiksi muistin varaaminen, luettelon lisääminen ja poistaminen). Työntekijälista-luokan periminen objektilistaluokasta ei ole tässä hyväksyttävää, koska saamme kaikki menetelmät (myös ne, joista emme ole kiinnostuneita). Lisäksi meidän on joissakin tapauksissa suoritettava tyyppivalua. Tyylikkäin tapa päästä tästä tilanteesta on delegoida jotkin objektiluetteloluokan menetelmistä työntekijäluetteloluokkaan. OOP-säännöissä on parasta esittää objektiluettelo työntekijäluettelon yksityisellä (yksityisellä) menetelmällä. Tässä tapauksessa luetteloon pääsee indeksoijan kautta.
Lähdeteksti C# käyttäen System ; käyttäen System.Collections.Generic ; käyttäen System.Linq ; käyttäen System.Text ; nimiavaruus Työntekijät { /// <summary> /// Luokka työntekijätietojen tallentamiseen. /// </summary> class Työntekijä { yksityinen merkkijono nimi ; yksityinen merkkijonoosasto ; _ public Työntekijä ( merkkijonon nimi , merkkijono osasto ) { this . nimi = nimi ; tämä . osasto = osasto ; } /// <yhteenveto> /// Työntekijän nimi. /// </summary> public string Nimi { get { return this . nimi ; } } /// <yhteenveto> /// Työosasto. /// </summary> public string Osasto { get { return this . osasto ; } } } /// <yhteenveto> /// Luokka työntekijöiden luettelon tallentamiseen. /// </summary> class Työntekijäluettelo { yksityinen luettelo < Työntekijä > työntekijät = new List < Työntekijä >(); /// <yhteenveto> /// Ominaisuus työntekijän saamiseen ja kirjoittamiseen indeksin mukaan. /// </summary> /// <param name="index">Työntekijäindeksi.</param> /// <returns>Työntekijä.</returns> public Työntekijä tämä [ int index ] { get { return työntekijät [ indeksi ]; } set { työntekijät [ indeksi ] = arvo ; } } /// <yhteenveto> /// Uuden työntekijän lisääminen. /// </summary> /// <param name="employee">Uusi työntekijä.</param > public void Lisää ( Työntekijä ) { työntekijää . Lisää ( työntekijä ); } /// <yhteenveto> /// Olemassa olevan työntekijän poistaminen. /// </summary> /// <param name="employee">Poistettava työntekijä.</param> public void Poista ( Työntekijän työntekijä ) { työntekijät . Poista ( työntekijä ); } /// <yhteenveto> /// Työntekijän peräkkäinen haku nimellä. /// </summary> /// <param name="name">Työntekijän nimi.</param> /// <param name="offset">Asema, josta haku aloitetaan.</param> // / < returns>Työntekijäindeksi.</returns> public int GetIndexOfEmployeeByName ( merkkijonon nimi , int offset = 0 ) { for ( int i = offset ; i < työntekijät . Count ; i ++) { if ( työntekijät [ i ]. Nimi == nimi ) { return i ; } } paluu - 1 ; } } class Ohjelma { static void Main ( string [] args ) { //Luo luettelo työntekijöistä ja lisää siihen merkintöjä EmployeesList empList = new EmployeesList (); empList . Lisää ( uusi työntekijä ( "Shlensky Dmitry" , "web-studio" )); empList . Lisää ( uusi työntekijä ( "Kusy Nazar" , "verkkostudio" )); empList . Lisää ( uusi työntekijä ( "Magpie Orest" , "verkkostudio" )); //Hae työntekijä Kusyi Nazar ja näytä tulos, kun haet alusta ja 2. aseman konsolista . WriteLine ( empList . GetIndexOfEmployeeByName ( "Kusy Nazar" ). ToString ()); konsoli . WriteLine ( empList . GetIndexOfEmployeeByName ( " Kusy Nazar " , 2 ). ToString ()); //Etsi ja poista työntekijä Soroka Orestes empList . Poista ( empList [ empList . GetIndexOfEmployeeByName ( " Harakka Orestes " )]); } } } Lähdeteksti kielellä C#2 käyttäen System ; käyttäen System.Collections.Generic ; käyttäen System.Linq ; käyttäen System.Text ; nimiavaruus Työntekijät { /// <summary> /// Luokka työntekijätietojen tallentamiseen. /// </summary> class Työntekijä { yksityinen merkkijono nimi ; yksityinen merkkijonoosasto ; _ public Työntekijä ( merkkijonon nimi , merkkijono osasto ) { this . nimi = nimi ; tämä . osasto = osasto ; } /// <yhteenveto> /// Työntekijän nimi. /// </summary> public string Nimi { get { return this . nimi ; } } /// <yhteenveto> /// Työosasto. /// </summary> public string Osasto { get { return this . osasto ; } } } /// <yhteenveto> /// Luokka työntekijöiden luettelon tallentamiseen. /// </summary> class Työntekijäluettelo { yksityinen luettelo < Työntekijä > työntekijät = new List < Työntekijä >(); /// <yhteenveto> /// Ominaisuus työntekijän saamiseen ja kirjoittamiseen indeksin mukaan. /// </summary> /// <param name="index">Työntekijäindeksi.</param> /// <returns>Työntekijä.</returns> public Työntekijä tämä [ int index ] { get { return työntekijät [ indeksi ]; } set { työntekijät [ indeksi ] = arvo ; } } /// <yhteenveto> /// Omaisuus työntekijän hankkimiseen ja kirjoittamiseen nimellä. /// </summary> /// <param name="name">Työntekijän nimi.</param> /// <returns>Ensimmäinen työntekijä, jonka nimi vastasi tai null</returns> julkinen Työntekijä tämä [ merkkijonon nimi ] { get { foreach ( Työntekijänimike työntekijöissä ) { if ( nimike . Nimi == nimi ) return item ; _ _ } return null ; } } /// <yhteenveto> /// Uuden työntekijän lisääminen. /// </summary> /// <param name="employee">Uusi työntekijä.</param > public void Lisää ( Työntekijä ) { työntekijää . Lisää ( työntekijä ); } /// <yhteenveto> /// Olemassa olevan työntekijän poistaminen. /// </summary> /// <param name="employee">Poistettava työntekijä.</param> public void Poista ( Työntekijän työntekijä ) { työntekijät . Poista ( työntekijä ); } /// <yhteenveto> /// Työntekijän peräkkäinen haku nimellä. /// </summary> /// <param name="name">Työntekijän nimi.</param> /// <param name="offset">Asema, josta haku aloitetaan.</param> // / < returns>Työntekijäindeksi.</returns> public int GetIndexOfEmployeeByName ( merkkijonon nimi , int offset ) { int indeksi = - 1 ; for ( int i = offset ; i < työntekijät . Count ; i ++ ) { if ( työntekijät [ i ]. Nimi == nimi ) { indeksi = i ; tauko ; } } paluuindeksi ; _ } /// <yhteenveto> /// Työntekijän peräkkäinen haku nimellä. /// </summary> /// <param name="name">Työntekijän nimi.</param> /// <returns>Työntekijäindeksi.</returns> public int GetIndexOfEmployeeByName ( merkkijonon nimi ) { return GetIndexOfEmployeeByName ( nimi , 0 ); } } class Ohjelma { static void Main ( string [] args ) { //Luo luettelo työntekijöistä ja lisää siihen merkintöjä EmployeesList empList = new EmployeesList (); empList . Lisää ( uusi työntekijä ( "Shlensky Dmitry" , "web-studio" )); empList . Lisää ( uusi työntekijä ( "Kusy Nazar" , "verkkostudio" )); empList . Lisää ( uusi työntekijä ( "Magpie Orest" , "verkkostudio" )); //Hae työntekijä Kusyi Nazar ja näytä tulos, kun haet alusta ja 2. aseman konsolista . WriteLine ( empList . GetIndexOfEmployeeByName ( "Kusy Nazar" ). ToString ()); konsoli . WriteLine ( empList . GetIndexOfEmployeeByName ( " Kusy Nazar " , 2 ). ToString ()); //Etsi ja poista työntekijä Soroka Orestes empList . Poista ( empList [ "Magpie Orestes" ]); } } }Tämä esimerkki on Object Pascal -versio yllä olevasta ei-triviaalista esimerkistä.
Lähdeteksti Object Pascalissa yksikkö Työnantajat ; käyttöliittymä käyttää Contnrs ; type // Luokka työntekijätietojen tallentamiseen TEmployee = class yksityinen FName : string ; FDepartament : string ; public konstruktori Luo ( nimi , osasto : merkkijono ) ; julkaistu ominaisuus Nimi : merkkijono lue FName ; ominaisuus Osasto : merkkijono lue FDepartament ; loppu ; // Luokka työntekijöiden luettelon tallentamiseen TEmployeersList = class yksityinen // Objektiluettelon luokan objekti FEmployeersList : TObjectList ; toiminto GetTemployee ( Indeksi : Kokonaisluku ) : TEmployee ; menettely SetEmployee ( Indeksi : Kokonaisluku ; const Arvo : TEmployee ) ; julkinen rakentaja Luo ; tuhoaja Tuhoa ; ohittaa ; toiminto Lisää ( Työntekijä : TEmployee ) : Kokonaisluku ; menettely Poista ( Työntekijä : TEmployee ) ; toiminto IndexEmployeeByName ( Nimi : merkkijono ; Offset : Kokonaisluku = 0 ) : Kokonaisluku ; ominaisuus Työntekijät [ Hakemisto : Kokonaisluku ] : TEmployee lukea GetTemployee kirjoittaa SetEmployee ; oletusarvo ; loppu ; toteutus {työntekijä} rakentaja TEtyöntekijä . Luo ( nimi , osasto : merkkijono ) ; begin FName := Nimi ; FDepartament := Osasto ; loppu ; { TemployeersList } rakentaja TEmployeersList . luoda ; begin // Luo objekti, jonka menetelmät delegoimme FEmployeersList := TObjectList . luoda ; loppu ; destructor TEmployeersList . Tuhoa ; aloita FEmployersList . Ilmainen ; perinnöllinen ; loppu ; toiminto TemployeersList . GetTemployee ( Indeksi : Kokonaisluku ) : TEmployee ; begin Tulos := FEmployeersList [ Index ] as TEmployee ; loppu ; menettely TEmployeersList . SetEmployee ( Indeksi : Kokonaisluku ; const Arvo : TEmployee ) ; begin FEmployeersList [ Hakemisto ] := Arvo ; loppu ; toiminto TemployeersList . IndexEmployeeByName ( Nimi : merkkijono ; Offset : Kokonaisluku = 0 ) : Kokonaisluku ; // Työntekijän peräkkäinen haku nimen perusteella // Offset-argumentin avulla voit määrittää paikan, josta haetaan. // Jos työntekijää ei löydy, se palauttaa arvon, joka on pienempi kuin nolla (-1) var Index : Integer ; alkaa Tulos := - 1 ; // Olettaen, että se ei ole luettelossa Index : = FEmployeersList . Count - 1 offset do if ( FEmployeersList [ Index ] as TEmployee ) . _ Nimi = Nimi ja aloita sitten Tulos := Hakemisto ; poistua ; loppu ; loppu ; toiminto TemployeersList . Lisää ( Työntekijä : TEmployee ) : Kokonaisluku ; begin Tulos := FEmployeersList . Lisää ( työntekijä ) ; loppu ; menettely TEmployeersList . Poista ( Työntekijä : TEmployee ) ; aloita FEmployersList . Poista ( työntekijä ) ; loppu ; loppua .Valitettavasti kaikki ohjelmoijat eivät käytä delegointimallia. Esimerkiksi Borland ( Delphi - ohjelmointiympäristön kehittäjä ) perusluokkakirjastossaan peri edellä mainitun TObjectList-objektiluetteloluokan TList - osoitinlistaluokasta . Tämä aiheutti tyytymättömyyttä joidenkin kokeneiden ohjelmoijien keskuudessa.
Tämä esimerkki on PHP -versio yllä olevasta yksinkertaisesta Java -esimerkistä .
PHP5 lähdekoodi <?php luokka A { public function f () { print "A: Kutsu menetelmä f()<br />" ; } public function g () { print "A: Kutsumme menetelmää g()<br />" ; } } luokka C { yksityinen $_a ; julkinen funktio __construct () { $this -> _a = new A ; } julkinen funktio f () { $this -> _a -> f (); } julkinen funktio g () { $this -> _a -> g (); } public function y () { print "C: kutsu menetelmä y()<br />" ; } } $obj = uusi C ; $obj -> f (); $obj -> g (); $obj -> y (); ?> Monimutkainen esimerkkiTämä esimerkki on PHP -versio yllä olevasta monimutkaisesta Java -esimerkistä .
PHP5 lähdekoodi <?php // käytä liitäntää tyypin turvarajapinnalle I { public function f (); julkinen tehtävä g (); } luokka A toteuttaa I { public function f () { print "A: Kutsu f()<br />" ; } public function g () { print "A: Kutsumme menetelmää g()<br />" ; } } luokka B toteuttaa I { public function f () { print "B: Kutsu f()<br />" ; } public function g () { print "B: Kutsu menetelmä g()<br />" ; } } luokka C toteuttaa I { yksityinen $_i ; // luo objekti, jonka menetelmille delegoidaan julkinen toiminto __construct () { $this -> _i = new A ; } // näillä menetelmillä muutamme kenttäobjektia , jonka menetelmillä delegoimme julkisen funktion A:lle () { $this -> _i = new A ; } julkinen funktio toB () { $this -> _i = new B ; } // delegoidut menetelmät public function f () { $this -> _i -> f (); } julkinen funktio g () { $this -> _i -> g (); } } $obj = uusi C ; $obj -> f (); $obj -> g (); $obj -> toB (); $obj -> f (); $obj -> g (); ?> Ei-triviaali esimerkkiTämä esimerkki on PHP -versio yllä olevasta ei-triviaalista esimerkistä.
PHP5 lähdekoodi <?php // luokka työntekijätietojen tallentamiseen class Työntekijä { yksityinen $_nimi ; yksityinen $_osasto ; julkinen funktio __konstrukti ( $nimi , $ osasto ) { $this -> _name = $nimi ; $this -> _departament = $ osasto ; } public function getName () { return $this -> _name ; } public function getDepartament () { return $this -> _departament ; } } // luokka objektiluettelon tallentamiseen class ObjectList { yksityinen $_objList ; julkinen funktio __construct () { $this -> free (); } /** *ei ole tylsää! */ julkinen funktio vapaa () { $this -> _objList = array (); } public function count () { paluumäärä ( $this - > _objList ); } julkinen funktio add ( $obj ) { array_push ( $this -> _objList , $obj ); } julkinen funktio poista ( $obj ) { $k = array_search ( $obj , $this -> _objList , true ); if ( $k !== false ) { unset ( $this -> _objList [ $k ] ); } } julkinen funktio get ( $indeksi ) { return $this -> _objList [ $index ]; } julkinen funktiojoukko ( $index , $obj ) { $this - > _objList [ $index ] = $obj ; } } // luokka työntekijöiden tallentamiseen class EmployeeList { // luokan objekti "objektien luettelo" yksityinen $_employeersList ; public function __construct (){ // luo objekti, jonka menetelmät delegoimme $this -> _employeersList = new ObjectList ; } public function getEmployer ( $indeksi ) { return $this -> _employeersList -> get ( $indeksi ); } julkinen funktio setEmployer ( $indeksi , työntekijä $objEmployer ) { $this -> _employeersList -> set ( $indeksi , $objEmployer ); } public function __destruct () { $this -> _employeersList -> free (); } julkinen funktio add ( Työntekijä $objEmployer ) { $this -> _employeersList -> add ( $objEmployer ); } julkinen toiminto poista ( Työntekijä $objEmployer ) { $this -> _employeersList -> poista ( $objEmployer ); } // peräkkäinen työntekijän haku nimellä // $offset-argumentin avulla voit asettaa paikan, josta haetaan. // jos työntekijää ei löydy, se palauttaa arvon, joka on pienempi kuin nolla (-1) julkinen funktio getIndexByName ( $nimi , $offset = 0 ) { $tulos = - 1 ; // oletetaan, että se ei ole luettelossa $cnt = $this -> _employeersList -> count (); for ( $i = $offset ; $i < $cnt ; $i ++ ) { if ( ! strcmp ( $nimi , $this -> _employeersList -> get ( $i ) -> getName () ) ) { $tulos = $i ; tauko ; } } return $tulos ; } } $obj1 = uusi työntekijä ( "Tanasiychuk Stepan" , "web-studio" ); $obj2 = uusi työntekijä ( "Kusy Nazar" , "verkkostudio" ); $obj3 = uusi työntekijä ( "Magpie Orest" , "web-studio" ); $objList = uusi Työntekijälista (); $objList -> add ( $obj1 ); $objList -> add ( $obj2 ); $objList -> add ( $obj3 ); echo "<pre>" ; print_r ( $objList ); echo "<hr>" ; $index = $objList -> getIndexByName ( "Kusy Nazar" ); $obj4 = $objList -> getEmployer ( $indeksi ); print_r ( $obj4 ); echo "<hr>" ; $objList -> setEmployer ( 2 , $obj4 ); print_r ( $objList ); echo "</pre>" ; ?>Lähdekoodi Pythonissa
#coding: utf-8 #python 3 luokka A : def f ( itse ): print ( 'A : kutsuva menetelmä f' ) def g ( itse ): print ( 'A : kutsuva menetelmä g' ) luokka C : def __init__ ( itse ): itse . A = A () def f ( itse ): palauta itse . A. _ f () def g ( itse ): palauta itse . A. _ g () c = C () c . f () #A: kutsumenetelmä f c . g () #A: kutsumenetelmä gSuunnittelumalleja | |
---|---|
Main | |
Generatiivinen | |
Rakenteellinen | |
Käyttäytyminen | |
Rinnakkaisohjelmointi _ |
|
arkkitehtoninen |
|
Java EE -mallit | |
Muut mallit | |
Kirjat | |
Persoonallisuudet |