Fachada (patrón de diseño)

La versión actual de la página aún no ha sido revisada por colaboradores experimentados y puede diferir significativamente de la versión revisada el 4 de julio de 2020; las comprobaciones requieren 5 ediciones .
Fachada
fachada
Tipo de estructural
Descrito en Patrones de diseño

El patrón de fachada ( eng.  Facade ) es un patrón de diseño estructural que le permite ocultar la complejidad del sistema al reducir todas las llamadas externas posibles a un objeto , delegándolas a los objetos correspondientes del sistema.

Descripción

Problema

¿Cómo proporcionar una interfaz unificada con un conjunto de implementaciones o interfaces dispares, por ejemplo, a un subsistema, si no se desea un fuerte acoplamiento a ese subsistema, o si la implementación del subsistema podría cambiar?

Solución

Defina un punto de interacción con el subsistema: un objeto de fachada que proporcione una interfaz común con el subsistema y confíele la responsabilidad de interactuar con sus componentes. Una fachada es un objeto externo que proporciona un único punto de entrada para los servicios del subsistema. La implementación de otros componentes del subsistema es privada y no es visible para los componentes externos. El objeto Facade proporciona la implementación GRASP del patrón de Variaciones Protegidas en términos de protección contra cambios en la implementación del subsistema.

Características de la aplicación

Una plantilla se utiliza para establecer algún tipo de política en otro grupo de objetos. Si la política debe ser brillante y notable, debe utilizar los servicios de la plantilla Fachada. Si es necesario proporcionar secreto y precisión (transparencia), el patrón Proxy es una opción más adecuada .

Ejemplos

C++

Texto fuente en C++ #incluir <iostream> #incluir <cadena> #include <memoria> #incluir <vista_cadena> /** Músico abstracto: no es una parte obligatoria del patrón, se introdujo para simplificar el código */ clase músico { const char * nombre ; público : Músico ( std :: string_viewname ) { _ esto -> nombre = nombre . datos (); } virtual ~ Músico () = predeterminado ; protegido : salida vacía ( std :: string_view texto ) { std :: cout << esto -> nombre << "" << texto << "." << estándar :: endl ; } }; /** Músicos específicos */ Vocalista de clase : Músico público { público : Vocalista ( std :: string_view nombre ) : Músico ( nombre ) {} void singCouplet ( int coupletNumber ) { std :: texto de cadena = "verso cantado #" ; text += std :: to_string ( coupletNumber ); salida ( texto ); } void cantarCoro () { salida ( "cantó el coro" ); } }; guitarrista de clase : músico público { público : Guitarrista ( std :: string_view nombre ) : Músico ( nombre ) {} void playCoolOpening () { salida ( "comienza con una introducción genial" ); } void jugarCoolRiffs () { salida ( "toca riffs geniales" ); } void reproducirAnotherCoolRiffs () { salida ( "reproduce otros riffs geniales" ); } void jugarIncreíblementeGenialSolo () { salida ( "produce un solo increíblemente genial" ); } void jugarFinalAccord () { salida ( "finaliza la canción con un acorde potente" ); } }; bajista de clase : músico público { público : Bajista ( std :: string_view nombre ) : Músico ( nombre ) {} void seguir los tambores () { salida ( "sigue los carretes" ); } void changeRhythm ( std :: string_viewtype ) { _ std :: string text = ( "cambiado al ritmo" ); texto += tipo ; texto += "a" ; salida ( texto ); } void dejar de jugar () { salida ( "deja de reproducir" ); } }; baterista de clase : músico público { público : Baterista ( std :: string_view nombre ) : Músico ( nombre ) {} void empezar a jugar () { salida ( "comienza a reproducir" ); } void dejar de jugar () { salida ( "deja de reproducir" ); } }; /** Fachada, en este caso una famosa banda de rock */ clase BlackSabbath { std :: unique_ptr < Vocalista > vocalista ; std :: unique_ptr < Guitarrista > guitarrista ; std :: unique_ptr < Bajista > bajista ; std :: unique_ptr < Baterista > baterista ; público : sábado negro () { vocalista = std :: make_unique < Vocalista > ( "Ozzy Osbourne" ); guitarrista = std :: make_unique < Guitarrista > ( "Tony Iommi" ); bajista = std :: make_unique < Bajista > ( "Geezer Butler" ); baterista = std :: make_unique < Baterista > ( "Bill Ward" ); } void playCoolSong () { guitarrista -> playCoolOpening (); baterista -> empezar a tocar (); bajista -> seguir a los tambores (); guitarrista -> playCoolRiffs (); vocalista -> cantarCouplet ( 1 ); bajista -> changeRhythm ( "coro" ); guitarrista -> tocarAnotherCoolRiffs (); vocalista -> cantarCoro (); bajista -> changeRhythm ( "verso" ); guitarrista -> playCoolRiffs (); vocalista -> cantarCouplet ( 2 ); bajista -> changeRhythm ( "coro" ); guitarrista -> tocarAnotherCoolRiffs (); vocalista -> cantarCoro (); bajista -> changeRhythm ( "verso" ); guitarrista -> tocarIncreíblementeCoolSolo (); guitarrista -> playCoolRiffs (); vocalista -> cantarCouplet ( 3 ); bajista -> changeRhythm ( "coro" ); guitarrista -> tocarAnotherCoolRiffs (); vocalista -> cantarCoro (); bajista -> changeRhythm ( "verso" ); guitarrista -> playCoolRiffs (); bajista -> dejar de tocar (); baterista -> dejar de tocar (); guitarrista -> tocarFinalAccord (); } }; int principal () { std :: cout << "SALIDA:" << std :: endl ; banda Black Sabbath ; banda _ reproducirCanciónFresca (); devolver 0 ; } /** * SALIDA: * Tony Iommi comienza con una introducción genial. * Bill Ward comienza a tocar. * Geezer Butler sigue la batería. * Tony Iommi toca grandes riffs. * Ozzy Osbourne cantó el verso #1. * Geezer Butler cambió al ritmo del coro. * Tony Iommi toca otros riffs geniales. * Ozzy Osbourne cantó el coro. * Geezer Butler cambió al ritmo del verso. * Tony Iommi toca grandes riffs. * Ozzy Osbourne cantó el verso #2. * Geezer Butler cambió al ritmo del coro. * Tony Iommi toca otros riffs geniales. * Ozzy Osbourne cantó el coro. * Geezer Butler cambió al ritmo del verso. * Tony Iommi ofrece un solo increíblemente genial. * Tony Iommi toca grandes riffs. * Ozzy Osbourne cantó el verso #3. * Geezer Butler cambió al ritmo del coro. * Tony Iommi toca otros riffs geniales. * Ozzy Osbourne cantó el coro. * Geezer Butler cambió al ritmo del verso. * Tony Iommi toca grandes riffs. * Geezer Butler deja de jugar. * Bill Ward deja de jugar. * Tony Iommi termina la canción con un potente acorde. */

JavaScript

Código fuente JavaScript /* Partes complejas */ function SubSystem1 () { this . método1 = función () { consola . log ( "SubSystem1.method1 llamado" ); }; } función SubSystem2 () { este . método2 = función () { consola . log ( "SubSystem2.method2 llamado" ); }; esto _ métodoB = función () { consola . log ( "SubSystem2.methodB llamado" ); }; } /* Fachada */ function Fachada () { var s1 = new SubSystem1 (), s2 = new SubSystem2 (); esto _ m1 = función () { consola . log ( "Fachada.m1 llamado" ); s1 . método1 (); s2 _ método2 (); }; esto _ m2 = función () { consola . log ( "Fachada.m2 llamado" ); s2 _ métodoB (); }; } /* Cliente */ prueba de función () { var fachada = nueva Fachada (); fachada _ m1 (); fachada _ m2 (); } prueba (); /* Salida: "Fachada.m1 llamado" "SubSistema1.método1 llamado" "SubSistema2.método2 llamado" "Fachada.m2 llamado" "SubSistema2.métodoB llamado" */

CoffeeScript

Texto fuente en lenguaje CoffeeScript # Clase de cargador de imágenes ImageLoader loadImage = (src) -> # ... constructor: (hash = {}) -> @images = {} @images [ nombre ] = loadImage ( src ) para nombre , src de hash # Clase de cargador de audio SoundLoader loadSound = (src) -> # ... constructor: (hash = {}) -> @sounds = {} @sounds [ name ] = loadSound ( src ) for name , src of hash # Constructor de cargador de clase Facade : ({imágenes, sonidos}) -> @images = nuevo ImageLoader ( imágenes ). imágenes @sounds = nuevo SoundLoader ( sonidos ). sonidos sonido: (nombre) -> @sounds [ nombre ] imagen: (nombre) -> @images [ nombre ]

PHP

codigo fuente php /** * Implementaciones de partes individuales de computadora. * Cada método de clase tiene algún tipo de implementación, en este ejemplo se omite. */ /** * Class CPU, responsable de ejecutar la CPU */ class CPU { public function freeze () {} public function jump ( $ position ) {} public function execute () {} } /** * Class Memory, responsable del funcionamiento de la memoria */ class Memory { const BOOT_ADDRESS = 0x0005 ; carga de función pública ( $posición , $datos ) {} } /** * Class HardDrive, responsable del funcionamiento del disco duro */ class HardDrive { const BOOT_SECTOR = 0x001 ; const SECTOR_SIZE = 64 ; lectura de función pública ( $ lba , $ tamaño ) {} } /** * Un ejemplo del patrón "Fachada" * La computadora se usa como un objeto unificado. * Detrás de este objeto se ocultarán todos los detalles del trabajo de sus partes internas. */ class Computadora { protected $cpu ; $memoria protegida ; disco duro protegido $ ; /** * Constructor de la computadora. * Inicializar partes */ public function __construct () { $this -> cpu = new CPU (); $esto -> memoria = nueva memoria (); $this -> disco duro = nuevo disco duro (); } /** * Manejo simplificado del comportamiento de "inicio de la computadora" */ public function startComputer () { $cpu = $this -> cpu ; $memoria = $esto -> memoria ; $disco duro = $esto -> disco duro ; $cpu -> congelar (); $memoria -> cargar ( $memoria :: BOOT_ADDRESS , $hardDrive -> read ( $hardDrive :: BOOT_SECTOR , $hardDrive :: SECTOR_SIZE ) ); $cpu -> saltar ( $memoria :: BOOT_ADDRESS ); $cpu -> ejecutar (); } } /** * Los usuarios de computadoras cuentan con una fachada (computadora) * que oculta toda la complejidad de trabajar con componentes individuales. */ $computadora = nueva Computadora (); $computadora -> iniciarComputadora ();

Pitón

Código fuente en Python # Partes complejas de la clase del sistema CPU ( objeto ): def __init__ ( self ): # ... pasar def congelar ( auto ): # ... pasar def saltar ( auto , dirección ): # ... pasar def ejecutar ( auto ): # ... pasar clase Memoria ( objeto ): def __init__ ( auto ): # ... pasar def cargar ( auto , posición , datos ): # ... pasar class HardDrive ( objeto ): def __init__ ( self ): # ... pasar def read ( self , lba , size ): # ... pasar # Clase de fachada Computadora ( objeto ): def __init__ ( self ): self . _cpu = cpu () auto . _memory = Memoria () self . _disco duro = disco duro () def iniciarComputadora ( self ): self . _cpu . congelar () auto . _memoria _ cargar ( BOOT_ADDRESS , self . _hardDrive . leer ( BOOT_SECTOR , SECTOR_SIZE )) self . _cpu . saltar ( BOOT_ADDRESS ) self . _cpu . ejecutar () # Lado del cliente si __name__ == "__main__" : fachada = Computadora () fachada . iniciarComputadora ()

C#

Texto fuente en C# utilizando el sistema ; biblioteca de espacio de nombres { /// <summary> /// clase de subsistema /// </summary> /// <comentarios> /// <li> /// <lu>implementa la funcionalidad del subsistema;</lu> /// <lu>hace el trabajo asignado por el objeto <see cref="Facade"/>;</lu> /// <lu>no "sabe" nada sobre la existencia de la fachada, es decir, no almacena referencias a él;</lu> / // </li> /// </remarks> clase interna SubsistemaA { cadena interna A1 () { return "Subsistema A, Método A1\n" ; } cadena interna A2 () { return "Subsistema A, Método A2\n" ; } } clase interna SubsistemaB { cadena interna B1 () { return "Subsistema B, Método B1\n" ; } } clase interna SubsystemC { cadena interna C1 () { return "Subsistema C, Método C1\n" ; } } } /// <summary> /// Fachada - fachada /// </summary> /// <comentarios> /// <li> /// <lu>"sabe" con qué clases de subsistema abordar la solicitud;< /lu > /// <lu>delegar las solicitudes de los clientes a los objetos apropiados dentro del subsistema;</lu> /// </li> /// </remarks> public class Facade { Library . SubsistemaA a = nueva biblioteca . SubsistemaA (); biblioteca _ SubsistemaB b = nueva biblioteca . SubsistemaB (); biblioteca _ SubsystemC c = nueva biblioteca . SubsistemaC (); public void Operation1 () { Consola . WriteLine ( "Operación 1\n" + a . A1 () + a . A2 () + b . B1 ()); } public void Operation2 () { Consola . WriteLine ( "Operación 2\n" + b . B1 () + c . C1 ()); } } class Program { static void Main ( string [] args ) { Fachada fachada = nueva Fachada (); fachada _ Operación1 (); fachada _ Operación2 (); // Esperar a la Consola del usuario . leer (); } }

Rubí

Texto fuente en lenguaje ruby Biblioteca de módulos # <summary> # Subsystem class # </summary> # <remarks> # <li> # <lu>implementa la funcionalidad del subsistema;</lu> # <lu>hace el trabajo asignado por <see cref="Facade"/> ;</lu> # <lu>no "sabe" nada sobre la existencia de la fachada, es decir, no almacena referencias a ella;</lu> # </li> # </remarks> class SubsystemA def a1 ; "Subsistema A, Método a1 \n " ; enddef a2 ; _ "Subsistema A, Método a2 \n " ; final final clase SubsistemaB def b1 ; "Subsistema B, Método b1 \n " ; final final clase SubsistemaC def c1 ; "Subsistema C, Método c1 \n " ; final final final # <summary> # Facade # </summary> # <remarks> # <li> # <lu>"sabe" a qué clases de subsistema dirigir las solicitudes;</lu> # <lu>delega las solicitudes a los clientes en los objetos apropiados dentro el subsistema ;</lu> # </li> # </remarks> clase Fachada def inicializar @a = Biblioteca :: SubsistemaA . nuevo ; @b = Biblioteca :: SubsistemaB . nuevo ; @c = Biblioteca :: SubsistemaC . nuevo ; final def operación1 pone "Operación 1 \n " + @a . a1 + @a . a2 + @b . final b1 def operación2 pone "Operación 2 \n " + @b . b1 () + @c . c1 () final final fachada = fachada . nueva fachada . operación1 fachada . operacion2 # Espere a que el usuario obtenga

VB.NET

Texto fuente en lenguaje VB.NET Biblioteca de espacios de nombres 'Clase de subsistema '. implementa la funcionalidad del subsistema ' . realiza el trabajo asignado por el objeto Fachada '. no "sabe" nada sobre la existencia de la fachada, es decir, no almacena referencias a ella Friend Class SubsystemA Friend Function A1 () As String Return "Subsystem A, Method A1" & vbCrLf End Function Función amiga A2 () Como cadena Devuelve "Subsistema A, Método A2" & vbCrLf Función final Clase final Amigo Clase SubsistemaB Amigo Función B1 () Como cadena Devuelve "Subsistema B, Método B1" & vbCrLf Función final Clase final Amigo Clase SubsistemaC Amigo Función C1 () Como cadena Devuelve "Subsistema C, Método C1" & vbCrLf Función final Clase final espacio de nombres final 'Fachada '. "sabe" qué clases de subsistema abordar la solicitud ' . delega las solicitudes de los clientes a los objetos apropiados dentro del subsistema Public NotInheritable Class Facade Sub privado Nuevo () End Sub Biblioteca compartida como nueva . _ SubsistemaA () Compartido b Como nueva biblioteca . SubsystemB () Compartido c Como nueva biblioteca . SubsistemaC () Suboperación pública compartida 1 ( ) Consola . WriteLine ( "Operación 1" & vbCrLf & a . A1 () & a . A2 () y b . B1 ()) Fin sub Suboperación pública compartida 2 ( ) Consola . WriteLine ( "Operación 2" & vbCrLf & b . B1 () & c . C1 ()) End Sub End Class programa de clase Sub principal compartido () Fachada . Operación1 () Fachada . Operación2 () 'Esperando la acción del usuario Consola . Lectura () End Sub End Class

Delfos

Texto fuente en Delphi programa Patrón de Fachada ; {$CONSOLA DE TIPO DE APLICACIÓN} utiliza SysUtils ; tipo TComputer = clase procedimiento público PlugIn ; procedimiento PowerMonitor ; procedimiento Poder ; fin ; procedimiento TComputer . enchufar ; begin WriteLn ( 'Incluido en la red' ) ; fin ; procedimiento TComputer . PowerMonitor ; begin WriteLn ( 'Enciende el monitor' ) ; fin ; procedimiento TComputer . poder ; begin WriteLn ( 'Enciende la unidad del sistema' ) ; fin ; escriba TNotebook = procedimiento de clase Power ; fin ; procedimiento TNotebook . poder ; comenzar WriteLn ( 'Presione el botón de encendido' ) ; fin ; tipo TKettle = complemento de procedimiento de clase ; procedimiento Poder ; fin ; procedimiento TKettle . poder ; comenzar WriteLn ( 'Presione el botón de encendido' ) ; fin ; procedimiento TKettle . enchufar ; begin WriteLn ( 'Incluido en la red' ) ; fin ; tipo TFacade = clase procedimiento público PowerOn ( aDevice : TObject ) ; fin ; procedimiento TFachada . PowerOn ( unDispositivo : TObject ) ; comenzar si aDevice es TComputer entonces con TComputer ( aDevice ) comience PlugIn ; _ PowerMonitor ; poder ; fin ; si aDevice es TNotebook entonces con TNotebook ( aDevice ) hacer Power ; si aDevice es TKettle entonces con TKettle ( aDevice ) comience PlugIn ; _ poder ; fin ; WriteLn end ; comience con TFacade . Crear intente PowerOn ( TComputer . Create ) ; _ Encendido ( TNotebook.Create ) ; _ _ Encendido ( TKettle.Create ) ; _ _ finalmente Libre ; fin ; Leerln ; fin _

Java

Fuente Java /* Partes complejas */ clase CPU { public void freeze () { System . fuera _ println ( "congelar" ); } public void jump ( posición larga ) { System . fuera _ println ( "posición de salto =" + posición ); } public void ejecutar () { System . fuera _ println ( "ejecutar" ); } } class Memory { public void load ( posición larga , byte [] datos ) { System . fuera _ println ( "cargar posición = " + posición + ", datos = " + datos ); } } class HardDrive { byte público [] leído ( long lba , int size ) { System . fuera _ println ( "leer lba = " + lba + ", tamaño = " + tamaño ); devolver nuevo byte [ tamaño ] ; } } /* fachada */ clase Computadora { privada final estática larga BOOT_ADDRESS = 1L ; privado final estático largo BOOT_SECTOR = 2L ; privado final estático int SECTOR_SIZE = 3 ; CPU CPU privada ; memoria privada ; _ disco duro privado disco duro ; Computadora pública () { this . cpu = nueva cpu (); esto _ memoria = nueva memoria (); esto _ disco duro = nuevo disco duro (); } public void startComputer () { cpu . congelar (); memoria _ cargar ( BOOT_ADDRESS , disco duro . leer ( BOOT_SECTOR , SECTOR_SIZE )); CPU _ saltar ( BOOT_ADDRESS ); CPU _ ejecutar (); } } /* Cliente */ aplicación de clase { public static void main ( String [] args ) { Computer computer = new Computer (); computadora _ iniciarEquipo (); } }

haxe

Texto de origen en idioma Haxe /** * Implementaciones de partes individuales de computadora. * Cada método de clase tiene algún tipo de implementación, en este ejemplo se omite. */ /** * Class CPU, responsable del funcionamiento del procesador */ class CPU { public function new () { } función pública congelar (): Void { //... } salto de función pública ( posición : Int ): Void { //... } función pública ejecutar (): Void { //... } } /** * Class Memory, responsable del funcionamiento de la memoria */ class Memory { public static inline var BOOT_ADDRESS : Int = 0x0005 ; función pública nueva () { } carga de función pública ( posición : Int , datos : haxe . io . Bytes ): Void { //... } } /** * Class HardDrive, responsable del funcionamiento del disco duro */ class HardDrive { public static inline var BOOT_SECTOR : Int = 0x001 ; public static inline var SECTOR_SIZE : Int = 64 ; función pública nueva () { } función pública de lectura ( lba : Int , tamaño : Int ): haxe . yo _ Bytes { //... devuelve nulo ; } } /** * Un ejemplo del patrón "Fachada" * La computadora se usa como un objeto unificado. * Detrás de este objeto se ocultarán todos los detalles del trabajo de sus partes internas. */ class Computadora { private var cpu : CPU ; memoria var privada : Memoria ; unidad de disco duro privada var : unidad de disco duro ; /** * Constructor de la computadora. * Inicializar partes */ función pública new () { this . cpu = nueva cpu (); esto _ memoria = nueva memoria (); esto _ disco duro = nuevo disco duro (); } /** * Manejo simplificado del comportamiento de "inicio de la computadora" */ public function startComputer (): Void { cpu . congelar (); memoria _ cargar ( Memoria . BOOT_ADDRESS , disco duro . leer ( Disco duro . BOOT_SECTOR , Disco duro . SECTOR_SIZE ) ); CPU _ saltar ( Memoria.BOOT_ADDRESS ) ; _ CPU _ ejecutar (); } } /** * Los usuarios de computadoras cuentan con una fachada (computadora) * que oculta toda la complejidad de trabajar con componentes individuales. */ class Application { public static function main (): Void { var computer : Computer = new Computer (); computadora _ iniciarEquipo (); } }

Rápido

Código fuente rápido // CPU de clase lógica { public func freeze () -> String { devuelve "Procesador de congelación". } public func jump ( posición : String ) -> String { return "Saltando a: \( posición ) " } función pública ejecutar () -> Cadena { devuelve "Ejecutando". } } memoria de clase { public func load ( posición : Cadena , datos : Cadena ) -> Cadena { return "Cargando desde \( posición ) datos: \( datos ) " } } disco duro de clase { public func read ( lba : String , size : String ) -> String { return "Algunos datos del sector \( lba ) con tamaño \( size ) " } } // Clase de fachada ComputerFacade { privado dejar cpu = CPU () privado dejar memoria = memoria () privado dejar disco duro = disco duro () inicio de función pública () { cpu . congelar () let ssd = disco duro . leer ( lba : "100" , tamaño : "1024" ) memoria . cargar ( posición : "0x00" , datos : ssd ) cpu . salto ( posición : "0x00" ) CPU . ejecutar () } } // Cliente let pc = ComputerFacade () pc . empezar ()

Literatura

  • E. Gamma, R. Helm, R. Johnson, J. Vlissides . Técnicas de diseño orientado a objetos. Patrones de Diseño = Patrones de Diseño: Elementos de Software Reutilizable Orientado a Objetos. - San Petersburgo. : " Pedro ", 2007. - S. 366. - ISBN 978-5-469-01136-1 . (también ISBN 5-272-00355-1 )

Fuentes y enlaces