Resumen Patron Composite

Embed Size (px)

Citation preview

ma de una imagen depende de las caractersticas de un dispositivo de visualizacin, concretamente de su capacidad de color y de suresolucin. Sin la.ayuda delos tendran que de-tenninar qu implementacinusar bajo varias c1rcunstanc1as en cada aphcac!n. Para aliviar a los desarrolladores de esta responsabilidad, AppKit proporc1ona un puenteNXI-mage/NXImageRep. NXlmage definela interfaz para manipularLa implementacin de las imgenes se define,en una jerarqua de clases separaJa NXJmageRep quesubclasesNXEP-SlmageRep, NXCachedl mageRep y NXBitMaplmageRep. t?'l mage una referenc1a a u?o o ms objetosNXJ mageRep.Sihayms de unaimplementacin de una NXlmage la msapropfada para eldispositivo de visualizacinactual.NXlmage es capazconvertir una implementacin enotra siesnecesario. Elaspecto interesante de esta Bndge es que NXImage puede almacenar ms de una implementacin de NXJmageRep alm1smotiempo. PATRONESRELACIONADOS ElpatrnAbstracl Factory (79)puede crear y configurar unBridge. ElpatrnAdapter( 131) est orientadoa conseguir quetrabajen juntas clasesnoestnrela-cionadas.Nonnalmente se aplica a sistemas que ya han sido diseados.El Bndge, otro la-do, se usa al comenzar un diseo para pennitir que abstrncciones e implementacionesvaren Indepen-dientemente unas de otras. ) ,. /

' - ......

... . ... ..... . . :::: . .. COMPOSITE (COMPUESTO) PROPSITO Estructural de Objetos C?mpone objetos enestructuras de rbolpararepresentar jerarquasde parte-todo.Permitequelos clientes traten demanera unifonne a los objetosindividuales y a los compuestos. MOnVACIN Las aplicaciones grficas como los editores de dibujo y los sistemas de diseo de circuitos penniten a los usuariosconstruir diagramas complejos apartir de componentes simples.Elusuario puedeagru-par componentes parafonnar componentes ms grandes, que a suvez puedenagruparse para fonnac componentes a_n mayores.Unaimplementacin simple podra definir clases para primitivasgrficas como Texto y Lmea,ms otras clases que acten como contenedoras de estas primitivas. Perohayunproblema con este enfoque:el cdigo que usa estas clases debe tratar de fonna dife-rente a los objetos primitivos y a los contenedores, incluso aunque la mayor parte del tiempo elusua-rio lostrate de formaidntica. Tener que distinguir entre estos objetos hace que la aplica.:in sea mis compleja. ElpatrnCompositt: describe cmo usar.ta composicinrecursiva para quelos clientesno tengan que hacer esta distincin. La clave del p:llrn_Cnmposite esuna clase abstrncta que representa tanto acomo asus contenedores.Para els1stema grfico, esta clase es Grafico.Grafico declara operaciones como Dibu-jar que son especficas de objetos grficos. Tambin declara operaciones que comparten todos los ob-jetos compuestos,tales como operaciones para acceder a sus hijos y para gestionarlos. Las subclases Linea,Rectanguloy Texto (vlase eldiagrama de clases siguiente) definen objetos grficos primitivos.Estas clases implementan Dibujar para dibujar trneas, rectngulos y texto, respec-tivamente.Como losgrficos primitivos notienen grficos hijos, ninguna de estas claSes implementa operaciones relacionadas conlos hijos. --11 LineaRectangulo Dibujar()Dibujar() Gral/ca Dibujar() Anadir(Grafico) Eliminar(Grafico) ObtenorHlfo(int) 1T TextoDibujo Dibujar()Dibujar() Madir(Gralico g) o-Eliminar(Gratlco) ObtenerHijo(int) gratlcos ......... ..... .. ...-----, . . . - - - - para todo g en grafteos g.Dibujar() ,52Patrones de Diseo 1 La claseDibujodefineunaagregacinde objetos Grafico. Dibujoimplementa Dibujar para que llame alDibujar de sus hijos, y aftade operaciones relacionadas conlos hijos. Como la interfaz de Di-bujoseajustaalainterfazdeGrafico,losobjetosDibujopuedencomponerrecursivamenteotros Dibujos. El siguientediagramamuestraunatfpicaestructuradeobjetoscompuestosrecursivamentepor otros objetos Grafio compuestos: . ;..J

1 Use el patrn Corilposite cuando ..: ... quiera representar jerarqufas de objetos parte-todo. quiera quetos clientes seancapaces de obviar lasdiferencias entre composiciones de objetos y losobjetos individuales.Los clientes tratarn a todoslosobjetos de la estructura compuesta de manera uniforme. ESTRUCTURA .1 r Cliente 1 Componente r Operacion() Anadir(Componente) Eliminar(Componen/o) ObtenerHijo(int) A r1 HojaCompuesto Operacion()Operacion()o- - - - - -Anadir(COmponente) Eliminar(Componente) ObtenerHijo(int) hijos --- -----para todo g en hijos g.Operacion(); ... :-r Patrones Estructurales153 Una estructura de objetos Compuestos tfpica puede parecersea esto: PARTICIPANTES Componente (Grafico) - declara lainterfaz de los objetos de la composicin. - implementa el comportamiento predeterminado de la interfaz que es comlln a todas las clases . - declara una interfaz para acceder a sus componentes hijos y gestionarlos. - (opcional) define una interfaz para acceder al padre deuncomponente en la estructura recur-siva y, si es necesario, la implementa. Hoja (Rectangulo, Linea, Texto, etc.) - reptsenta objetos hoja en la composicin.Una hoja no tiene hijos. - define el comportamiento delosobjetos primitivos de la composicin. Compuesto (Dibujo) - define el comportamientode los componentes que tienenhijos. - almacena componentes hijos. - implementa las operaciones de la interfaz Componente relacionadas con tos hijos. CUente - manipula objetos en la composicin a travs de la interfaz Componente. COLABORACIONES Los Clientes usanla interfaz de la clase Componente parainteractuar contos objetos de ta estructura compuesta.Siel recipiente es una Hoja, lapeticinse trata correctamente. Si es unCompuesto,nor-malmenteredirigelaspeticionesa suscomponenteshijos, posiblemente realizando operacionesadi-cionales antes o despus. CONSECUENCIAS El patrn Composite define jerarqufas de clasesformadaspor objetosprimitivosy compuestos.Los objetos primiti-vos pueden componerse en otros objetos ms complejos, que a su vez pueden ser compuestos, y asf de manera recurrente. All donde el cdigo espere unobjeto primitivo, tambinpodr recibir un objeto compuesto. simplifica el cliente.Los clientes pueden tratar unifonnemente alas estructuras compuestas y a los objetos individuales. Los clientes normalmente no conocen (y no les deberfaimportar) si es-tn tratando conuna hoj:1 o conuncomponente compuesto. Esto simplifica el cdigo del clien-te, puesto que evita tener que escribir funciones coninstrucciones 1 fanidadas enlas clases que definenla composicin. facilita aliad ir nuevos tipos de componentes. Si se definen nuevas subclases Compuesto u Hoja. tstas funcionarn automticamente con las y el cdigo cliente existentes. No hay que cambiar los clientespara lasnuevas clases COmponente. puede hacer que un diseilo sea demasiado general. La desventaja de facilitar aliad ir nuevos com-ponentes es que hace m.s diffcil restringir los componentes de uncompuesto. A veces queremos que un compuesto slo tenga ciertos componentes.Con elpatrnComposite, no podemos con-fiar en el sistema de tipos para que haga cumplir estas restricciones por nosotros. Envez de eso, tendremos que usar comprobaciones en tiempo de ejecucin. IMPLEMENTACIN Haymuchascuestiones a tener en cuenta alimplementar elpatrnComposite: l.Refertncias explfcirasal padre.Mantener referencias delos componenteshijosa suspadres puedesimplificar elrecorrido y la gestin de una e.strucrura referencia al facilitaascend9 porla estructuray borrar un componente. Lasreferenc1asalpadretamb1n ayudana implementar elpatrn Chain of Responsibility (205). Ellugar habitualdonde definirla referenciaalpadrees enla clase Componente.Lasclases Hoja y Co'mpuesto puedenheredar la referencia y las operaciones queIn gestionan. Conreferencias alpadre, es esencial mantener el invariante deque todos los hijos de un com-puesto tienen como padre alcompuesto que a su vez los tiene a ellos como hijos. El modo ms fcilde garantizar esto es cambiar el padre de un componente slo cuilndo seailade o se eli -mina a4!stede uncompuesto.Si se puedeimplementar unavez enlas operaciones Anadir y Eliminar de J;clase Compuesto entonces puede ser heredadopor todaslas subclases, conser-vando automticamente elinvariante. 2.Compartir componentes.Muchilsveceses til comp:u-lir componentes,por ejemplo parare-duci(los requisitos dealCllilcenamiento.Pero cuandouncomponenteno puedetenerm.sde un padre, compartir componentes se hace ms diffcil. Una posible solucin es que los hijos :dmacenen mltiples padres.Pero eso puedellevarnos a ambigedadescuandoSepropagaunapeticinhaciaarribaenlaestructura.Elpatrn Flyweight (179)muestra cmo adaptar undiseno para evitar guardar los padres. Funciona en casos enlos quelos hijos pueden evitar enviar peticiones alpadre extemalizando parte de su estado, o todo. 3.MaximiuJr lainterfat Componente.Uno delosobjetivosdelpatrnComposite eshacer que losclientes sedespreocupende lasclases Hojao Compuesto que estnusando.Paraconse-guirlo,laclaseComponentedeberladefinirtantasoperaciones comunesalasclasesCom-puesto yHoja como sea posible.La clase Componentenonnalmenteproporcionaimplemen-taciones predetenninadas para estas operaciones, que sern redefinidas por las subclasesHoja y Compuesto. Noobstante, este objetivoa vecesentra en conflicto conelprincipio dedisei'lo de jerarqufas declasesquediceque unaclaseslo deberadefinir operaciones quetienensentidoensus subclases.Haymuchas operacionespennitidas por Componente quenoparecen tener sentido enlas clasesHoja. Cmo puede Componente proporcionar una implementacinpredetermi-nada para ellas? .. i. A veces unpoco de creatividadmuestra cmo un; operacin que podra parecer que slo tie-ne enelcaso delosCompuestospuede implementarsepara todoslosCOmponentes, mov1ndola a la clase Componente. Por ejemplo, la inteaz para acceder a los hijos es una par-tefundamentaldela clase Compuesto, pero no de las clasesHoja. Pero si vemos a unaHoja comounComponente que nuncatiene hijos,podemos definir una opercinpredeterminada enla claseComponenteparaacceder a loshijos quenunca devuelveningnhijo. Las clases Hoja pueden usar esa implementacin predeterminada.peroJs clases Compuesto la reimplc-mentarn p01raque devuelva sus hijos. Las operaciones de gestin de los hijos son ms problemticas, y se trotan en el siguiente punto. 4.Declarar las operaciones de gest6n dt los hijos. Aunquela clase Compuesto implemellla las operaciones A nadir y Elinnar para controlar loshijos, un aspecto imponante del patrn Com-puesto es qu4! clases declaran estas operaciones en la jerorqufa de clases Compuesto. Debera-mos declarar estasoperaciones en elComponentey hacer que tuvieran sentido enlasclases Hoja, o deberamosdeclararlas y definirlas slo enCompuesto y sus subclases? La decisinimplica un equilibrio entre seguridad y transparencia: la interfaz de gestin de los hijos enla rafz de la jerarqufa de clases nos da transpa-rencia, puestoquepodemostratar 01 todoslos componentes demanerauniforme.Sinem-bargo, sacrifica la seguridad, ya que los clientes puedenintentar hacer cosas sin sentido, co-mo ailadir y eliminar objetos de lashojas. Definir In gestin de los hijos en la clase Compuesto nos proporciona seguridad, ya que cual-quier intento de ailadir o eliminar objetos del01s hojas ser detectado en tiempo de compilu-cin enunlenguaje estticamente tipado, como C++.Perotransparencia,porque lashojasy los compuestos tienen interfaces diferentes. Eneste patrnhemos dadomsimportancia a la trnnsparencia que a la seguridad.Siseopta porlaseguridad, habr ocasiones enlasque perderemosinformacinsobre eltipo y tendre-mosque convertirun componenteenuncompuesto. Cmopodemoshacerlosinrecurrir a una conversin que no Sl:a segura conrespecto altipo? Una posibilidad es declar;u- una operacin COilpuestoObtenarCompuasto()en la clase Compo-nente.El Componente proporciona un.1 operacin por omisin que devuelve unpuntero nulo.La clase Compuesto redefine esta operacin para devolverse a sf misma a travis de su punterothis: classCo11puesto classC0111ponanta public: 1/ .. virtualCompuestoObtenar Compuesto()(r eturne} } ; classCompuesto:publicComponente public: }i voidAnadir(Componenta') 11... - virtualCompuestoObtenerCompuesto(){returnthis;} classHojapublicComponente 11. } ; ;Patrones doDiseo nos permite consultar a uncomponente para ver si es uncompuesto.Po-demos ejecutar Anadir y EU111lnar con seguridad sobre el compuesto que devuelve. uncoapuestonewHo jaunaHojanewHoja , Componente prueba; unC0111ponenteunCompuesto; if(pruebaunComponente >ObtenerCompuesto()) Hoja); unComponente11(pruebaunComponente>ObtenerCompuesto()) prueba>Anadir(newHoja)://noaunahoja Se pueden hacer c9mprobaciones similares para un Compuesto usando la consttuccin de C++ dynamic_cast.) Por supuesto,(:Vproblemaaqul esquenotrotamos atodosloscomponentes demnnerauni-forme.TenemOs que volver a realizar comprobaciones para diferentes tipos antes de empren-der la acci, apropinda. La nicaforma de proporcionar 1ransparencia es definir operaciones predeterminadas Anadlr i Eliminar en Componente. Eso crea unnuevo problema:nohay modo de implementar Com ponente: :Anadir sin in1roducir asl mismo la posibilidad de que falte. Podramos no hacer na-da. pero eso omite una consideracinimportante; es decir, unintento de aiiadir algo a una ho-ja probablemente indicandounerror.En ese caso,laoperncin Anadir produce basura. PodamQS hacer que borrara suargumento, pero eso. no eslo quelos clientes espe!llll. Normalmenteesmejor hacer que Anadir y Eluinarfallende manerapredeterminada (tal vez !:miando una si el componente nopuede tener hijos o si el argumento de Eli inar no es unhijo del componente. Otro posibilidadescambiar ligeramente el significado de "eliminar". Si el componenteman-tiene unn referencia alpadre podamos redefinir Co111ponente: :El1 1nar para eliminarse n se mismo de su padre. No obstante, sigue sin haber unn interpretacin con sentido para Anadir. S.Debeda implementar el Componenteunalista de Componentes? Podamos estar tentados de definir elconjunto dehijos como una variable de instancia de la claseComponente enla que se dectnie las operaciones de acceso y gestin-de tos hijos. Pero poner elpuntero alhi jo en Inclase base incurre en un11penalizacin de espacio para cada hoja, incluso aunque una hojanuncatengahijos. Esto slomerecelapena si hayrelativamente pocos hijos enla es ttuctura. 6.Ordenacinde los hijos.Muchosdiseilosespecificanuna ordenacindeloshijosde:Com puesto. Enel ejemplo delGrafico,la ordenacin puede reflejar elorden desde elfrentehasta el fondo. Silos objetos Compuesto representan rboles de anlisis, entonces lasinsttucciones compuestas pueden ser instancias de un Compuesto cuyos hijos deben estar ordenados de mil nera que renejen elprograma. Cu11ndoInordenacinde los hijos esuna cuesdna 1ener en cuenta,debemos discnar las in-tences de acceso y gestin de hijos cuidadosamente para conlrolar Insecuenciade hijos.El pa!Cnllerador (237)puede servimos degufil. .. ; 1: 1 1 ... r ' '' Patrones Estructurales157 7.Cach paramejorar el rendimiento.Sinecesitamosrecorrer composiciones o buscar en ellas con .frecuencia, la clase Compuesto puede almacenar informacin sobre sushijos que facilite el recorrido olab(isqueda,El Compuestopuedeguardar resultados o simplementeinforma-cinque lepermita evitar parte delrecorrido o delabsqueda.Por ejemplo.la claseDibujo delejemplodela seccin de Motivacin poda guardar la caja limtrofe de sushijos.Mien-tras se dibuja o es seleccionado, esta caja previamente guardada permite que Dibujo no tenga que dibujar o realiz.ar bsquedas cuando sus hijos no son visibles en laventano actual . Los cambios en uncomponente nequerir.in inval idar lade sus padres. Esto funciona me-jor cuando los componentes conocen 11 su!t podres. Por tanto, si se va a usar almacenamiento ca-se necesita definir una intcd'az para decirle a los compuestos que su ya no es vlida. 8.Quindeberlaborrarloscomponentt!s?Enlenguajessinrecoleccindebasura,normal-mente es mejor hacer que un Compuesto sea el responsable de borrar sus hijos cuando es des-truido.Una n estareglaescuandolosobjetosHojasoninmutables y puedenpor tanto ser compartidos. 9. Cl es lamejor estructura de datos paraalmacenar loscomponentes?Los objetos Com-puestopuedenusarmuchnsestructurasdedatosdiferentespara almacenar sushijos,inclu yendolistasenlazadas,rboles,arraysy tablas dedispersin.La eleccindeloestrucrura de datos depende (como siempre) de la eficiencia. De hecho, ni siquiera es necesario usar una es-tructum de datos de propsito general. Avecesloscompuestostienenunavariable paracada hijo, aunque esto requiere que cada subclase de Compuesto implemente su propiaiiuerfaz de gestin. Vase el patrnlnterpreter (225) para un ejemplo. CDIGODEEJEMPLO Determinados equipos,como computadoresy componentes suelenestar organizadosen jerar-quras de parte-todo o depertenencia.Por ejemplo, unchasispuede contener unidades y placas base, un bus puede contener tarjetas y unarmario puede contener chasis. buses, etctera. Dichas estructuras pue-den modelarse de manera natural con elpalrn Composite. Ll claseEquipo define unainterf:12. paratodos los equipos de la jerarqua de parte-todo. cl assEquipo{ public: virtual-Equipo() constcharNombre (){return_nombre virtualVatioPotencia() virtualMonedaPrecioNeto() virtualMonedaPrecioConOescuento() virtualvoidAnadir(Equipo); virtualvoidEliminar(Equipo virtualIteradorCrearltorador() protected: Equipo(constchar): private: constchar_nombre; } i Equipo decJara operaciones que devuelvenlosde un equipo, como su consumo y coste.Las subclases implementan esw operaciones para determinados tipos de equipos.Equipo tambit!n decla-ra una operncin Crearlterador que devuelve un Iterador (vase el Apt!ndice C) para acceder a sus pQJ'tes. La implementacin predetennin:lda de esta operacin devuelve un IteradorNulo, que itera so. bre el conjunto vado. Las subclases d.eEquipo podranincluir clases Hoja que representen unidades de disco, circuitos integrados e interruptores: classDiSquetera:publicEquipo{. public: }j Disquetera(constchar ) virtual-Disquetera() virtualVatioPotencia() virtualMonedaPrecioNeto() virt'ualMonedaPre'cioConDescuento() EquipoCompuestoesla clasebasede los equiposque contienen otros equipos.E.slambit!nunasub-clase de Equipo. 'o c.lassEquipoComp(es to:publicEquipo 1 public:./ virtual : -EquipoColllpuesto() / virtualVatioPotencia() virtualUonedaPreciONetO() virtualMonedaPrecioConOescuento() virtualvoidAnadir(Equipo) virtualvoidEliinar(Equipo virtualIteradorCrearlterador()i protect'ed: EquipoCompuesto(constchar private: Lista_equipo; } i EquipoCompuesto define las operaciones para acceder a sus componentes y recorrerlos.Las operacio-nes Anadir yEli111inarinsertan yborranequipos enla lista de equipos almacenados en elmiembro _equipo. La operacin Crearlterador devuelve un iterador (concretamente, una instancia deItera dorLista) para recorrer la lisia. Una implementacinpredeterminada de PrecioNeto podrausarCrearl terador para los preciosnetos de los equipos que lo componcn:l MonedaEquipoCompuesto::PrecioNeto(){ IteradriCrearlterador() J Es fkit olvi\bl'IC de bocnr ditc:r.tdor urna vu que seh.:a us.:wJo. El pOLttn muc:stn. en la p.igina 24S, cmo protegerse con1u 11 lcsCI'f'Of'e.S. r ., .!. 1 : Monedatotale; for(!>Primero()li>HaTerinado()i>Siguiente()) total+=i>EleentoAetual() >PrecioNeto() deletei retumtotal Ahora podemos representar unchasis de computadora como una subclase de EquipoCo111puesto lla-mada Chasis. Chasis hereda lasoperaciones relativas a los hijos de EquipoCopuesto. classChasis:publicEquipoCompuesto public: } Chasis(constchar ) virtual-Chasis() virt ualVatioPotencia() virtualMonedaPrecioNeto() virtualMonedaPrecioConoeseuento() Podemos delinir otros contenedores de equipos tales corno Armarioy Bus de forma similar. Eso nos da todo lonecesario para enSllmblar componentes en una computadora personal (bastante sencillo): Armarioar11ario:newArmario(ArariodePC' ); Chasischasis=newChasis( ' ChasisdePC' ) armario>Anadir(ehasis) BusbusnewBus('BusMCA' ) bus>Anadir(newTarjeta( ' TokenRingde16Mbs'lli chasis>Anadir(bus) chasis>Anadir(newOisquetera( ' Disqueterade3,5pulgadas' )) coutdy UpeNive, f\w.,acale, docloU'MM uf, lhclrlut rormaa. tOme U1cftC. wp shon: ol wla,obju lo() tq:WCICMuct. e:hlni:Jct tnd cbc.f-stkvdilhc Te-" anJ I""J)hk:acould be tn:Med u i(cwmlylth()