Intenție

  • Compuneți obiectele în structuri arborescente pentru a reprezenta ierarhii întregi. Compunerea permite clienților să trateze în mod uniform obiectele individuale șicompozițiile de obiecte.
  • Compoziție recursivă
  • „Anuarele conțin intrări, fiecare dintre acestea putând fi un director.”
  • 1-la-mulțime „are a” până la ierarhia „este a”

Problemă

Aplicația trebuie să manipuleze o colecție ierarhică de obiecte „primitive” și „compuse”. Prelucrarea unui obiect primitiv este tratată într-un singur mod, iar prelucrarea unui obiect compozit este tratată în mod diferit.Nu este de dorit să fie nevoie să se interogheze „tipul” fiecărui obiect înainte de a încerca să îl prelucreze.

Discuție

Definiți o clasă de bază abstractă (Component) care să specifice comportamentul care trebuie să fie exercitat în mod uniform pentru toate obiectele primitive și compozite. Subclasați clasele Primitive și Compozite din clasa Component. Fiecare obiect Composite se „cuplează” numai cu tipul abstract Component în timp ce își gestionează „copiii”.

Utilizați acest model ori de câte ori aveți „compozite care conțin componente, fiecare dintre acestea putând fi un compozit”.

Metodele de gestionare a copiilor ar trebui să fie definite în mod normal în clasa Composite. Din nefericire, dorința de a trata primitivele și compozitele în mod uniform impune ca aceste metode să fie mutate în clasa abstractă Component. A se vedea secțiunea „Opinii” de mai jos pentru o discuție despre problemele de „siguranță” față de cele de „transparență”.

Structură

Compozite care conțin Componente, fiecare dintre acestea putând fi unCompozit.

Menușuri care conțin elemente de meniu, fiecare dintre acestea putând fi un meniu.

Manageri de aspect GUI cu coloană de rând care conțin widget-uri, fiecare dintre acestea putând fi un manager de aspect GUI cu coloană de rând.

Directoare care conțin fișiere, fiecare dintre acestea putând fi un director.

Containere care conțin elemente, fiecare dintre acestea putând fi un container.

Exemplu

Compozitul compune obiecte în structuri arborescente și permite clienților să trateze obiecte individuale și compoziții în mod uniform. Deșiexemplul este abstract, expresiile aritmetice sunt Compozite. O expresie aritmetică este formată dintr-un operand, un operator (+ – * /),și un alt operand. Operandul poate fi un număr sau o altă expresie aritmetică. Astfel, 2 + 3 și (2 + 3) + (4 * 6) sunt ambele expresii valide.

Listă de verificare

  1. Asigurați-vă că problema dvs. se referă la reprezentarea relațiilor ierarhice „întreg-parte”
  2. Considerați euristica: „Containere care conțin containere,fiecare dintre acestea putând fi un container”. De exemplu, „Ansambluri care conțin componente, fiecare dintre ele putând fi un ansamblu.” Împărțiți conceptele domeniului dumneavoastră în clase de containere și clase de containere.
  3. Creați o interfață cu „cel mai mic numitor comun” care face ca containerele și containerele dumneavoastră să fie interschimbabile. Aceasta ar trebui să precizeze comportamentul care trebuie să fie exercitat în mod uniform în toate obiectele container și container.
  4. Toate clasele container și container declară o relație de tip „este un” cu interfața.
  5. Toate clasele container declară o relație de tip „are un” cu interfața.
  6. Clasele container utilizează polimorfismul pentru a delega la obiectele lor container.
  7. Metodele de gestionare a copiilor ar trebui să fie definite în mod normal în clasa Composite. Din păcate, dorința de a trata în mod uniform obiectele Leaf și Composite poate necesita ca aceste metode să fie promovate în clasa abstractă Component. A se vedea Gang ofFour pentru o discuție despre aceste compromisuri între „siguranță” și „transparență”.

Reguli generale

  • Composite și Decorator au diagrame de structură similare, reflectând faptul că ambele se bazează pe compoziția recursivă pentru a organiza un număr nelimitat de obiecte.
  • Composite poate fi parcursă cu Iterator. Vizitatorul poate aplica o operație asupra unui compozit. Composite ar putea utiliza Chain ofResponsibility pentru a permite componentelor să acceseze proprietățile globale prin intermediul părintelui lor. Ar putea, de asemenea, să folosească Decorator pentru a suprascrie aceste proprietăți asupra părților componente ale compoziției. Ar putea folosi Observer pentru a lega o structură de obiect de alta și State pentru a permite unei componente să își schimbe comportamentul pe măsură ce starea sa se schimbă.
  • Composite vă poate permite să compuneți un Mediator din bucăți mai mici prin compoziție recursivă.
  • Decorator este conceput pentru a vă permite să adăugați responsabilități la obiecte fără a le subclasa. Accentul lui Composite nu este pus pe înfrumusețare, ci pereprezentare. Aceste intenții sunt distincte, dar complementare.În consecință, Composite și Decorator sunt adesea folosite împreună.
  • Flyweight este adesea combinat cu Composite pentru a implementa noduri de frunze partajate.

Opinii

Toată ideea modelului Composite este că Composite poate fi creat atomic, exact ca o frunză. Dacă doriți să furnizați un protocolIterator, foarte bine, dar cred că acest lucru este în afara modelului în sine. În centrul acestui model se află capacitatea unui client de a efectua operații asupra unui obiect fără a fi nevoie să știe că există mai multe obiecte în interior.

Puterea de a trata o colecție eterogenă de obiecte în mod atomic (sau transparent) necesită ca interfața de „gestionare a copiilor” să fie definită la rădăcina ierarhiei clasei Composite (clasa abstractă Composite). Cu toate acestea, această alegere vă costă siguranța, deoarece clienții pot încerca să facă lucruri lipsite de sens, cum ar fi adăugarea și eliminarea de obiecte din obiectele frunză. Pe de altă parte, dacă „proiectați pentru siguranță”, interfața de gestionare a copiilor este declarată în clasa Composite și pierdeți transparența, deoarece frunzele și Composites au acum interfețe diferite.

Implementațiile Smalltalk ale modelului Composite nu au, de obicei, interfața de gestionare a componentelor în interfața Component, ci în interfața Composite. Implementările C++ tind să o pună în interfața Component. Acesta este un fapt extrem de interesant, la care mă gândesc adesea. Pot oferi teorii pentru a-l explica, dar nimeni nu știe cu siguranță de ce este adevărat.

Classele mele Component nu știu că există Composite. Ele nu oferă nici un ajutor pentru navigarea în Compozite, nici un ajutor pentru modificarea conținutului unui compozit. Acest lucru se datorează faptului că aș dori ca clasa de bază (și toate derivatele sale) să fie reutilizabile în contexte care nu necesită Composite. În cazul în care mi se dă un pointer la o clasă de bază, dacă am neapărat nevoie să știu dacă este sau nu un Composite, voi folosi dynamic_cast pentru a afla acest lucru. În acele cazuri în care dynamic_cast este prea costisitor, voi folosi un Visitor.

Legătură comună: „dacă împing interfața Composite în clasaComposite, cum voi enumera (adică voi traversa) o structură complexă?” Răspunsul meu este că atunci când am comportamente care se aplică la ierarhii precum cea prezentată în modelul Composite, folosesc în mod atipic Vizitatorul, astfel încât enumerarea nu este o problemă – Vizitatorul știe, în fiecare caz, exact cu ce tip de obiect are de-a face. Vizitatorul nu are nevoie ca fiecare obiect să furnizeze o interfață de enumerare.

Composite nu vă obligă să tratați toate componentele ca fiind Composite. Vă spune doar să puneți toate operațiile pe care doriți să le tratați „uniform” în clasa Component. Dacă operațiile de adăugare, eliminare și alte operații similare nu pot sau nu trebuie să fie tratate în mod uniform, atunci nu le puneți în clasa de bază Component. Nu uitați, apropo, că diagrama de structură a fiecărui model nu definește modelul, ci doar descrie ceea ce, din experiența noastră, este o realizare comună a acestuia. Doar pentru că diagrama de structură a lui Composite prezintă operațiile de gestionare a copiilor în clasa de bază Component nu înseamnă că toate implementările modelului trebuie să facă același lucru.

Susțineți site-ul nostru gratuit și dețineți cartea electronică!

  • 22 tipare de design și 8 principii explicate în profunzime
  • 406 pagini bine structurate, ușor de citit, fără jargon
  • 228 ilustrații și diagrame clare și utile
  • O arhivă cu exemple de cod în 4 limbaje
  • Toate dispozitivele acceptate: Formatele EPUB/MOBI/PDF

Aflați mai multe…

Lasă un răspuns

Adresa ta de email nu va fi publicată.