Delegație | |
---|---|
delegație | |
Descris în Design Patterns | Nu |
Delegarea este un model de proiectare de bază în care un obiect exprimă în exterior un anumit comportament , dar în realitate transferă responsabilitatea de a efectua acest comportament unui obiect înrudit. Modelul de delegare este abstractizarea fundamentală pe baza căreia sunt implementate celelalte modele - compoziție (numită și agregare), mixuri și aspecte .
Abilitatea de a schimba comportamentul unei anumite instanțe a unui obiect în loc de a crea o nouă clasă prin moștenire.
În general, acest tipar face dificilă optimizarea vitezei în favoarea purității abstracției îmbunătățite.
Deși delegarea nu este acceptată de limbajul Java, este suportată de multe medii de dezvoltare [1] .
În acest exemplu Java , clasa Bare o metodă stub care transmite metode către . Clasa pretinde că are atribute de clasă . foo()bar()ABA
Text sursă în java clasa A { void foo () { Sistem . afară . println ( "A: metoda foo() numită" ); } void bar () { System . afară . println ( "A: metoda bar() numită" ); } } class B { // Creați un obiect ale cărui metode vor delega comportamentul. A a = nou 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 (); } } Exemplu complexFolosind interfețe , delegarea se poate face într-un mod mai flexibil și mai sigur de tip . În acest exemplu, clasa Cpoate delega Afie către B. Clasa Care metode de comutare între clase Ași B. Includerea extensiei de implementare îmbunătățește siguranța tipului, deoarece fiecare clasă trebuie să implementeze metodele din interfață. Principalul dezavantaj este mai mult cod.
Să luăm un exemplu. Să presupunem că trebuie să implementați un cronometru în așa fel încât o anumită funcție să fie apelată după o anumită perioadă de timp. Programatorul temporizatorului dorește să ofere o atribuire de funcție utilizatorilor clasei sale (alți programatori).
Text sursă în java /** * Interfața descrie acțiunea care va fi apelată când apare evenimentul * timer. */ interfață TimerAction { void onTime (); } clasa WakeUpAction implementează TimerAction { @Override public void onTime () { System . afară . println ( "E timpul să te trezești!" ); } } clasa ChickenIsReadyAction implementează TimerAction { @Override public void onTime () { System . afară . println ( "Puiul este gata!" ); } } /** * Clasa de cronometru. În anumite condiții, TimerAction este apelat. */ class Timer { TimerAction action ; /** * O funcție pe care programatorul o apelează pentru a seta ora. */ void run () { if ( isTime ()) { action . onTime (); } } /** * O anumită funcție care are grijă de lucrul permanent. Implementarea sa * nu este interesantă în acest context. * * @return */ private boolean isTime () { return true ; } public static void main ( String [] args ) { Sistem . afară . println ( "Introduceți tipul de acțiune:" ); Scanner scanner = scaner nou ( System . in ); String actionType = scaner . nextLine (); Timer timer = timer nou (); if ( actionType . equalsIgnoreCase ( „setează cronometrul de trezire” )) { timer . action = new WakeUpAction (); } else if ( actionType . equalsIgnoreCase ( „setează cronometrul de pui” )) { timer . action = new ChickenIsReadyAction (); } cronometru . alerga (); }Acest exemplu este o versiune C++ a exemplului Java complex de mai sus. Deoarece C++ nu are un construct de interfață, clasa complet abstractă joacă același rol . Avantajele și dezavantajele sunt practic aceleași ca în exemplul Java.
Text sursă în c++ #include <iostream> clasa I { public : vid virtual f () = 0 ; gol virtual g () = 0 ; }; clasa A : public I { public : void f () { std :: cout << "A: apelarea metodei f()" << std :: endl ; } void g () { std :: cout << "A: apel metoda g()" << std :: endl ; } }; clasa B : public I { public : void f () { std :: cout << "B: apel metoda f()" << std :: endl ; } void g () { std :: cout << "B: apel metoda g()" << std :: endl ; } }; clasa C : public I { public : // Constructor C () : m_i ( nou A () ) { } // Destructor virtual ~ C () { șterge m_i ; } void f () { m_i -> f (); } void g () { m_i -> g (); } // Cu aceste metode schimbam obiectul-camp, ale carui metode le vom delega void lui A () { șterge m_i ; m_i = nouA ( ); } void toB () { șterge m_i ; m_i = nou B (); } privat : // Declaram un obiect ale carui metode le vom delega I * m_i ; }; int main () { C c ; c . f (); c . g (); c . toB (); c . f (); c . g (); returnează 0 ; } /* Ieșire: A: apelați metoda f() A: apelați metoda g() B: apelați metoda f() B: apelați metoda g() */Acesta este un exemplu de caz des întâlnit în practică. Există o sarcină de a crea o clasă pentru stocarea listei de angajați. Datele fiecărui angajat sunt stocate într-un obiect din clasa Employee. Există o clasă gata făcută și standard pentru stocarea unei liste de obiecte Employee. A implementat deja mecanisme de lucru cu lista (de exemplu, alocarea memoriei, adăugarea și eliminarea din listă). Moștenirea clasei liste de angajați din clasa listă de obiecte nu este acceptabilă aici, deoarece vom obține toate metodele (chiar și cele care nu ne interesează). În plus, va trebui să efectuăm turnarea tip în unele cazuri. Cea mai elegantă cale de ieșire din acest caz este de a delega unele dintre metodele clasei listă de obiecte către clasa listă de angajați. În regulile POO, cel mai bine este să reprezentați lista de obiecte cu o metodă privată (privată) a listei de angajați. În acest caz, lista poate fi accesată printr-un indexator.
Text sursă în C# folosind System ; folosind System.Collections.Generic ; folosind System.Linq ; folosind System.Text ; namespace Angajații { /// <rezumat> /// Clasă pentru stocarea datelor angajaților. /// </summary> class Employee { private string name ; departament privat string ; Angajat public ( nume șir , departament șir ) { this . nume = nume ; aceasta . departament = departament ; } /// <rezumat> /// Numele angajatului. /// </summary> șir public Nume { get { return this . nume ; } } /// <rezumat> /// Departamentul de lucru. /// </summary> public șir Departament { get { return this . departament ; } } } /// <rezumat> /// Clasă pentru stocarea unei liste de angajați. /// </summary> class EmployeesList { private List < Employee > employees = new List < Employee >(); /// <rezumat> /// Proprietate pentru obținerea și scrierea unui angajat după index. /// </summary> /// <param name="index">Indexul angajaților.</param> /// <returns>Angajat.</returns> public Angajat this [ int index ] { get { return employees [ index ]; } set { angajati [ index ] = valoare ; } } /// <rezumat> /// Adăugarea unui nou angajat. /// </summary> /// <param name="employee">Angajat nou.</param> public void Adaugă ( Angajat angajat ) { angajați . Adaugă ( angajat ); } /// <rezumat> /// Ștergerea unui angajat existent. /// </summary> /// <param name="employee">Angajatul de eliminat.</param> public void Remove ( Angajat angajat ) { angajați . Eliminați ( angajat ); } /// <rezumat> /// Căutare secvenţială a unui angajat după nume. /// </summary> /// <param name="name">Numele angajatului.</param> /// <param name="offset">Poziție din care începeți căutarea.</param> // / < returnează>Indexul angajaților.</returns> public int GetIndexOfEmployeeByName ( nume șir , int offset = 0 ) { for ( int i = offset ; i < angajați . Număr ; i ++) { if ( angajați [ i ]. Nume == nume ) { return i ; } } return - 1 ; } } class Program { static void Main ( string [] args ) { //Creează o listă de angajați și adaugă intrări la ea EmployeesList empList = new EmployeesList (); empList . Adăugați ( angajat nou ( "Shlensky Dmitry" , "studio web" )); empList . Adăugați ( angajat nou ( „Kusy Nazar” , „studio web” )); empList . Adăugați ( angajat nou ( „Magpie Orest” , „studio web” )); //Căutați angajatul Kusyi Nazar și afișați rezultatul când căutați de la început și din poziția a 2-a Consolă . WriteLine ( empList . GetIndexOfEmployeeByName ( "Kusy Nazar" ). ToString ()); Consola . WriteLine ( empList . GetIndexOfEmployeeByName ( "Kusy Nazar" , 2 ). ToString ()); //Căutați și ștergeți angajatul Soroka Orestes empList . Eliminați ( empList [ empList . GetIndexOfEmployeeByName ( „Magpie Orestes” )]); } } } Text sursă în C# 2 folosind System ; folosind System.Collections.Generic ; folosind System.Linq ; folosind System.Text ; namespace Angajații { /// <rezumat> /// Clasă pentru stocarea datelor angajaților. /// </summary> class Employee { private string name ; departament privat string ; Angajat public ( nume șir , departament șir ) { this . nume = nume ; aceasta . departament = departament ; } /// <rezumat> /// Numele angajatului. /// </summary> șir public Nume { get { return this . nume ; } } /// <rezumat> /// Departamentul de lucru. /// </summary> public șir Departament { get { return this . departament ; } } } /// <rezumat> /// Clasă pentru stocarea unei liste de angajați. /// </summary> class EmployeesList { private List < Employee > employees = new List < Employee >(); /// <rezumat> /// Proprietate pentru obținerea și scrierea unui angajat după index. /// </summary> /// <param name="index">Indexul angajaților.</param> /// <returns>Angajat.</returns> public Angajat this [ int index ] { get { return employees [ index ]; } set { angajati [ index ] = valoare ; } } /// <rezumat> /// Proprietate pentru obținerea și scrierea unui angajat după nume. /// </summary> /// <param name="name">Numele angajatului.</param> /// <returns>Primul angajat al cărui nume se potrivește sau nul</returns> public Angajat acest [ string name ] { get { foreach ( element de angajat în angajați ) { if ( item . Nume == nume ) return item ; } return null ; } } /// <rezumat> /// Adăugarea unui nou angajat. /// </summary> /// <param name="employee">Angajat nou.</param> public void Adaugă ( Angajat angajat ) { angajați . Adaugă ( angajat ); } /// <rezumat> /// Ștergerea unui angajat existent. /// </summary> /// <param name="employee">Angajatul de eliminat.</param> public void Remove ( Angajat angajat ) { angajați . Eliminați ( angajat ); } /// <rezumat> /// Căutare secvenţială a unui angajat după nume. /// </summary> /// <param name="name">Numele angajatului.</param> /// <param name="offset">Poziție din care începeți căutarea.</param> // / < returnează>Indexul angajaților.</returns> public int GetIndexOfEmployeeByName ( nume șir , int offset ) { int index = - 1 ; for ( int i = offset ; i < angajați . Număr ; i ++) { if ( angajați [ i ]. Nume == nume ) { index = i ; rupe ; } } return index ; } /// <rezumat> /// Căutare secvenţială a unui angajat după nume. /// </summary> /// <param name="name">Numele angajatului.</param> /// <returns>Indexul angajaților.</returns> public int GetIndexOfEmployeeByName ( string name ) { return GetIndexOfEmployeeByName ( nume , 0 ); } } class Program { static void Main ( string [] args ) { //Creează o listă de angajați și adaugă intrări la ea EmployeesList empList = new EmployeesList (); empList . Adăugați ( angajat nou ( "Shlensky Dmitry" , "studio web" )); empList . Adăugați ( angajat nou ( „Kusy Nazar” , „studio web” )); empList . Adăugați ( angajat nou ( „Magpie Orest” , „studio web” )); //Căutați angajatul Kusyi Nazar și afișați rezultatul când căutați de la început și din poziția a 2-a Consolă . WriteLine ( empList . GetIndexOfEmployeeByName ( "Kusy Nazar" ). ToString ()); Consola . WriteLine ( empList . GetIndexOfEmployeeByName ( "Kusy Nazar" , 2 ). ToString ()); //Căutați și ștergeți angajatul Soroka Orestes empList . Remove ( empList [ "Magpie Orestes" ]); } } }Acest exemplu este o versiune Object Pascal a exemplului non-trivial de mai sus.
Textul sursă în Object Pascal unitate UnitEmployers ; interfata folosește Contnrs ; tip // Clasa pentru stocarea datelor angajatului TEmployee = class private FName : string ; FDepartament : string ; constructor public Creare ( Nume , Departament : şir ) ; proprietate publicată Nume : șir de caractere citit FName ; proprietate Departament : șir citit FDepartament ; sfârşitul ; // Clasa de stocare a listei de angajați TEmployeersList = class private // Obiect al clasei „liste de obiecte” FEmployeersList : TObjectList ; function GetEmployee ( Index : Integer ) : TEmployee ; procedura SetEmployee ( Index : Integer ; const Value : TEmployee ) ; constructor public Creare ; destructor Distruge ; suprascrie ; function Add ( Angajat : TEmployee ) : Integer ; procedura Eliminare ( Angajat : TEmployee ) ; funcția IndexEmployeeByName ( Nume : șir ; Offset : Integer = 0 ) : Integer ; proprietate Angajati [ Index : Integer ] : TEmployee citeste GetEmployee scrie SetEmployee ; implicit ; sfârşitul ; implementare {angajat} constructor TEmployee . Creare ( Nume , Departament : şir ) ; începe FName := Nume ; FDepartament := Departament ; sfârşitul ; { Lista angajatilor } constructor TEmployeersList . a crea ; begin // Creați un obiect ale cărui metode le vom delega FEmployeersList := TObjectList . a crea ; sfârşitul ; destructor TEmployeersList . Distruge ; începe FEmployersList . Gratuit ; moștenit ; sfârşitul ; funcția TemployeersList . GetEmployee ( Index : Integer ) : TEmployee ; începe Rezultatul := FEmployeersList [ Index ] ca TEmployee ; sfârşitul ; procedura TEmployeersList . SetEmployee ( Index : Integer ; const Value : TEmployee ) ; începe FEmployeersList [ Index ] := Valoare ; sfârşitul ; funcția TemployeersList . IndexEmployeeByName ( Nume : șir ; Offset : Integer = 0 ) : Integer ; // Căutare secvenţială a unui angajat după nume // Prin argumentul Offset, puteţi seta poziţia din care să căutaţi. // Dacă angajatul nu este găsit, va returna o valoare mai mică decât zero (-1) var Index : Integer ; începe Rezultatul := - 1 ; // Presupunând că nu este în lista pentru Index := FEmployeersList . Numărătoarea inversă până la Offset do if ( FEmployeersList [ Index ] ca TEmployee ) . Nume = Nume apoi începe Rezultat := Index ; ieșire ; sfârşitul ; sfârşitul ; funcția TemployeersList . Adăugați ( Angajat : TEmployee ) : Întregul ; începe Rezultatul := FEmployeersList . Adaugă ( Angajat ) ; sfârşitul ; procedura TEmployeersList . Eliminare ( Angajat : TEmployee ) ; începe FEmployersList . Eliminare ( angajat ) ; sfârşitul ; sfârşitul .Din păcate, nu toți programatorii folosesc modelul de delegare. De exemplu, Borland (dezvoltatorul mediului de programare Delphi ) în biblioteca sa standard de clasă a moștenit clasa de listă de obiecte TObjectList menționată mai sus din clasa de listă de pointer TList . Acest lucru a provocat nemulțumiri în rândul unor programatori experimentați.
Acest exemplu este o versiune PHP a exemplului Java simplu de mai sus.
Cod sursă PHP5 <?php clasa A { public function f () { print "A: Apeleaza metoda f()<br />" ; } public function g () { print "A: Apelam metoda g()<br />" ; } } clasa C { privat $_a ; function public __construct () { $this -> _a = new A ; } function public f () { $this -> _a -> f (); } function public g () { $this -> _a -> g (); } public function y () { print "C: apel metoda y()<br />" ; } } $obj = nou C ; $obj -> f (); $obj -> g (); $obj -> y (); ?> Exemplu complexAcest exemplu este o versiune PHP a exemplului Java complex de mai sus.
Cod sursă PHP5 <?php // folosește interfața pentru tipul interfață de siguranță I { public function f (); funcţie publică g (); } clasa A implementează I { public function f () { print "A: Call f()<br />" ; } public function g () { print "A: Apelam metoda g()<br />" ; } } clasa B implementează I { public function f () { print "B: Call f()<br />" ; } public function g () { print "B: Apeleaza metoda g()<br />" ; } } implementează clasa C I { private $_i ; // creăm un obiect ale cărui metode vor fi delegate public function __construct () { $this -> _i = new A ; } // cu aceste metode schimbăm câmpul-obiect, ale cărui metode le vom delega funcția publică luiA () { $this -> _i = new A ; } function public toB () { $this -> _i = new B ; } // metode delegate public function f () { $this -> _i -> f (); } function public g () { $this -> _i -> g (); } } $obj = nou C ; $obj -> f (); $obj -> g (); $obj -> toB (); $obj -> f (); $obj -> g (); ?> Exemplu non-trivialAcest exemplu este o versiune PHP a exemplului non-trivial de mai sus.
Cod sursă PHP5 <?php // clasă pentru stocarea datelor angajaților clasa Employee { private $_name ; private $_department ; function public __construct ( $nume , $departament ) { $this -> _name = $nume ; $this -> _departament = $departament ; } public function getName () { return $this -> _name ; } public function getDepartament () { return $this -> _departament ; } } // clasa pentru stocarea unei liste de obiecte clasa ObjectList { private $_objList ; function public __construct () { $this -> free (); } /** *sa nu te plictisesti! */ 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 ] ); } } function public get ( $index ) { return $this -> _objList [ $index ]; } set de funcții publice ( $index , $obj ) { $this -> _objList [ $index ] = $obj ; } } // clasa pentru stocarea angajaților clasa EmployeeList { // obiect al clasei "lista de obiecte" private $_employeersList ; funcția publică __construct (){ // creăm un obiect ale cărui metode le vom delega $this -> _employeersList = new ObjectList ; } public function getEmployer ( $index ) { return $this -> _employeersList -> get ( $index ); } public function setAngajator ( $index , Angajat $objAngajator ) { $this -> _employeersList -> set ( $index , $objAngajator ); } public function __destruct () { $this -> _employeersList -> free (); } public function add ( Angajat $objAngajator ) { $this -> _employeersList -> add ( $objAngajator ); } public function remove ( Angajat $objAngajator ) { $this -> _employeersList -> remove ( $objAngajator ); } // căutare secvențială a unui angajat după nume // prin argumentul $offset, puteți seta poziția din care să căutați. // dacă angajatul nu este găsit, va returna o valoare mai mică decât zero (-1) funcția publică getIndexByName ( $nume , $offset = 0 ) { $rezultat = - 1 ; // presupunem că nu este în listă $cnt = $this -> _employeersList -> count (); pentru ( $i = $offset ; $i < $cnt ; $i ++ ) { if ( ! strcmp ( $nume , $acest -> _employeersList -> get ( $i ) -> getName () ) ) { $rezultat = $i ; rupe ; } } returnează $rezultat ; } } $obj1 = nou angajat ( „Tanasiychuk Stepan” , „studio web” ); $obj2 = nou angajat ( "Kusy Nazar" , "studio web" ); $obj3 = nou angajat ( "Magpie Orest" , "web studio" ); $objList = new EmployeeList (); $objList -> add ( $obj1 ); $objList -> add ( $obj2 ); $objList -> add ( $obj3 ); echo "<pre>" ; print_r ( $objList ); ecou „<hr>” ; $index = $objList -> getIndexByName ( "Kusy Nazar" ); $obj4 = $objList -> getEmployer ( $index ); print_r ( $obj4 ); ecou „<hr>” ; $objList -> setEmployer ( 2 , $obj4 ); print_r ( $objList ); ecou „</pre>” ; ?>Cod sursă în Python
#coding: utf-8 #python 3 clasa A : def f ( self ): print ( 'A: metoda de apelare f' ) def g ( self ): print ( 'A: metoda de apelare g' ) clasa C : def __init__ ( sine ): sine . A = A () def f ( self ): return self . A. _ f () def g ( self ): return self . A. _ g () c = C () c . f () #A: apel metoda f c . g () #A: metoda apelului gModele de design | |
---|---|
Principal | |
Generativ | |
Structural | |
Comportamental | |
Programare în paralel |
|
arhitectural |
|
Șabloane Java EE | |
Alte șabloane | |
Cărți | |
Personalități |