Singleton

En enxeñaría de software, o padrón de deseño Singleton (Instancia Única) emprégase para garantir que unha clase soamente teña unha instancia, ademais de proporcionar un punto de acceso global a esa instancia.

Trátase polo tanto dun padrón de creación.

É de utilidade cando se necesita exactamente un obxecto para coordinar accións nun sistema. Este concepto pode xeneralizarse para restrinxir a instanciación a un certo número de obxectos.

Motivación

En certos contextos, é importante que algunhas clases teñan exactamente unha instancia que sexa facilmente accesible (por exemplo, ter un único xestor de ventás nunha aplicación).

O uso dunha variable global fai accesible un obxecto, pero non evita que se poidan crear múltiples instancias de obxectos. Unha solución mellor é facer que sexa a propia clase a responsable da súa única instancia. A clase pode garantir que non se poida crear ningunha outra instancia (restrinxindo o acceso ao construtor) e pode así mesmo proporcionar un modo de acceso á instancia.

Aplicabilidade

O uso do padrón é axeitado cando:

  • Deba existir unha única instancia dunha clase, que debe ser accesible aos clientes dende un punto de acceso ben coñecido.
  • A única instancia pode ser estendida (subclase), e os clientes deberían poder utilizar a instancia estendida sen modificar o seu código.

Estrutura

Singleton 

Participantes

  • Instancia Única (Singleton): define un método de clase que permite aos clientes accederen á instancia única. Normalmente é responsable de crear a súa única instancia.

Colaboracións

Os clientes acceden á instancia do Singleton a través da operación definida con esa finalidade.

Consecuencias

As principais vantaxes do padrón Singleton son:

  • Proporciona un acceso controlado á súa única instancia grazas á encapsulación da mesma, podendo ter un control estrito sobre o acceso a ela por parte dos clientes.
  • Reduce o espazo de nomes ao evitar o uso de variables globais para almacenar instancias.
  • Posibilita o refinamento de operacións e representación; é dicir, pódense crear subclases da clase Singleton, sendo sinxelo configurar os sistemas cunha instancia desta clase estendida.
  • Permite un número variable de instancias, sendo necesario cambiar unicamente a operación que proporciona acceso á instancia do Singleton.
  • Outorga unha maior flexibilidade con respecto ás operacións de clase, pois o uso destas dificulta o cambio dos deseños para permitir máis dunha instancia.

Implementación

Á hora de utilizar o padrón Singleton, débense ter en conta algúns aspectos de implementación, entre os que destacan:

  • Garantir a unicidade da instancia da clase.
  • Estender a clase Singleton.

Garantir a unicidade da instancia da clase

O padrón Singleton fai que a única instancia sexa unha instancia normal da clase, pero coa particularidade de que dita clase soamente permite crear unha instancia. Adóitase conseguir isto mediante a ocultación da operación que crea a instancia tras unha operación de clase. Esta operación ten acceso á variable que contén a instancia e asegura que a variable estea inicializada con dita instancia previamente a devolver o seu valor. Este enfoque asegura que un Singleton se crea e inicializa antes do seu primeiro uso. Por exemplo, en Java pódese definir a operación de clase mediante un método estático obterInstancia() da clase Singleton, que tamén define unha variable estática _instancia que contén a súa única instancia.

public class Singleton {     private static Singleton _instancia = null;      private Singleton() {}      public static synchronized Singleton obterInstancia() {         if (_instancia == null) {             _instancia = new Singleton();         }         return _instancia;     } } 

Os clientes acceden ao Singleton exclusivamente a través do método obterInstancia(). A variable _instancia inicialízase a null e o método estático obterInstancia() devolve o seu valor, inicializándoa coa única instancia en caso de que sexa null. obterInstancia() utiliza inicialización "preguiceira" (lazy initialization): o valor que devolve non se crea e almacena ata que se accede a el por primeira vez.

Por outra banda, o construtor declárase como privado: un cliente que trate de crear unha instancia de Singleton directamente obterá un erro en tempo de compilación. Isto garante que soamente se pode crear unha instancia. Ademais, e debido a que _instancia é de tipo Singleton, o método obterInstancia() pode asignar a esta variable unha instancia dunha subclase de Singleton.

Nótese o uso de synchronized para permitir a súa utilización en aplicacións multi-fío. No caso de que dous fíos executen o método de creación simultaneamente cando a instancia do Singleton aínda non existe, ambos deben comprobar a instancia do Singleton e soamente debe creala un deles. Por iso é típico o uso de exclusión mutua na clase que indica que o obxecto está sendo instanciado.

Unha alternativa sería o uso de inicialización "impaciente" (eager initialization), na que sempre se crea a instancia. Este tipo de inicialización emprégase cando o programa sempre necesita unha instancia ou cando o custo de crear a instancia non é demasiado alto en términos de tempo/recursos.

public class Singleton {     private static Singleton _instancia = new Singleton();      private Singleton() {    }      public static Singleton obterInstancia() {         return _instancia;     } } 

Este método ten varias vantaxes:

  • Non se necesita utilizar synchronized no método obterInstancia().
  • O programador non ten que preocuparse da creación de instancias, pois Java garante que a inicialización xa estará feita antes de que o código sexa accedido por calquera clase.

Porén, tamén ten algúns inconvenientes. Destaca principalmente:

  • Se o programa non necesita a instancia do Singleton, pode ser unha mellor opción o uso da inicialización "preguiceira".

Estender a clase Singleton

O principal problema non é definir a subclase, senón crear a súa única instancia de maneira que os clientes a poidan utilizar. En esencia, a variable que fai referencia á única instancia debe ser inicializada cunha instancia da subclase. A técnica máis sinxela é determinar que Singleton queremos usar na operación obterInstancia() de Singleton.

Outra maneira de elixir a subclase de Singleton é trasladar a implementación de obterInstancia() dende a clase pai á subclase. Este enfoque dificulta a elección da clase de Singleton en tempo de execución, mentres que utilizar instrucións condicionais para determinar a subclase é máis flexible, pero fixa o conxunto de posibles clases Singleton. Ningún dos dous enfoques é o suficientemente flexible para tódolos casos.

Un enfoque máis flexible utiliza un rexistro de obxectos Singleton. Así, en lugar de que sexa obterInstancia() quen defina o conxunto de posibles clases Singleton, estas clases poden rexistrar a súa única instancia polo seu nome nun rexistro que sexa coñecido por todos.

O rexistro establece unha correspondencia entre nomes e obxectos Singleton. Cando obterInstancia() necesita un Singleton, consulta o seu rexistro, pedindo un Singleton polo seu nome. O rexistro busca o Singleton correspondente (no caso de que exista) e devólveo. Así, obterInstancia() non ten que coñecer tódalas posibles clases de Singleton. Todo o que necesita é unha interface común para tódalas clases de Singleton que inclúa operacións para o rexistro.

Exemplos de implementación

Java

A continuación amósase un exemplo no que se utiliza o padrón Singleton. Trátase dunha táboa onde claves e valores son cadeas de caracteres. O padrón Singleton garante que tódolos clientes utilizarán soamente a instancia única, é dicir, a mesma táboa hash (utilizada internamente para representar a táboa asociativa).

class Main {      static void buscar() {          // Obsérvese que en lugar de crear un obxecto de tipo Dicionario (o cal é         // imposible debido a que o construtor é privado) o que se fai é chamar         // ao método de clase instancia() para obter a instancia única.         Dicionario d = Dicionario.instancia();          System.out.println("O valor asociado a can é " + d.buscar("can"));         System.out.println("O valor asociado a oso é " + d.buscar("oso"));     }      static void engadir() {         Dicionario d = Dicionario.instancia();          d.engadir("gato", "cat");         d.engadir("can",  "dog");         d.engadir("rato", "mouse");         d.engadir("oso",  "bear");         d.engadir("león", "lyon");     }      static public void main(String argv[]) {         engadir();         buscar();     } }  class Dicionario {      // A clase Singleton garda un atributo de clase, normalmente privado, que     // mantén a referencia coa única instancia da clase.     static private Dicionario _instancia;      // Estado privado asociado coa instancia única.     private Hashtable _taboa;      // O construtor da clase, que crea a táboa de dispersión, é privado     // para garantir que non se poidan crear instancias dende fóra da clase.     private Dicionario() {         _taboa = new Hashtable();     }      // O método de clase instancia() encárgase de crear a instancia     // asociada ao Singleton a primeira vez que se solicita. En accesos     // posteriores, devólvese a instancia orixinal.     static Dicionario instancia() {         if (_instancia == null) {             _instancia = new Dicionario();         }          return _instancia;     }      // Estes dous métodos son aplicables sobre obxectos da clase Dicionario,     // é dicir, a súa única instancia. Engaden e buscan elementos na táboa hash.     // Dado que a táboa hash almacena obxectos de tipo Object (igual que o     // vector) debemos facer unha conversión ao extraer elementos da táboa.      public void engadir(String clave, String valor) {          _taboa.put(clave, valor);      }      public String buscar(String clave) {          return (String) _taboa.get(clave);      } } 

Padróns relacionados

  • Algúns dos padróns que se poden implementar facendo uso do Singleton son o Abstract Factory (Fábrica Abstracta), o Builder (Construtor virtual) e o Prototype (Prototipo).
  • Tamén é habitual que os obxectos Facade (Fachada) sexan Singletons debido a que soamente se require un obxecto Facade.

Véxase tamén

Bibliografía

  • Design Patterns. Elements of Reusable Object-Oriented Software - Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides - Addison Wesley (GoF- Gang of Four)

Outros artigos

Tags:

Singleton MotivaciónSingleton AplicabilidadeSingleton EstruturaSingleton ParticipantesSingleton ColaboraciónsSingleton ConsecuenciasSingleton ImplementaciónSingleton Exemplos de implementaciónSingleton Padróns relacionadosSingleton Véxase taménSingletonClase swEnxeñaría de softwarePadrón de deseño

🔥 Trending searches on Wiki Galego:

Rocío LeiraManuel RivasMeteoGaliciaLisímaco de AlexandríaSegunda guerra mundialOs demostrativos galegosFrancisco FumegaMexacánRocco SiffrediDesviación típicaLugoCosta da MorteNeolíticoCharles DarwinMarcos PereiroMariano RajoyAlfonso RuedaCeutaFermin MuguruzaCirrio comúnEstadio Municipal de RiazorMahatma GandhiIlla de SálvoraJoselu MatoCórdoba, EspañaBreixoNordés (vento)Río UllaEstadio Jan BreydelManuel María Puga PargaLista de paísesO sabor das margaridasOurenseDavid BowieQuerela das mulleresAmieiroXosé Luís Méndez FerrínJosé Antonio Primo de RiveraDía do LibroStellantisJosé de RiberaOs EoasXosé Ramón Fernández-OxeaPili PampínThe Times of IndiaOrlando BloomPoloniaBidueiroAgustín Fernández PazCorea do NorteTomiño (planta)Iker MuniainAdolfo SuárezA CoruñaArte posmodernaFillas de CassandraArcos, CuntisParadigmas dos verbos irregulares galegosFerroAtlánticaPosicións sexuaisTrevo brancoGalaicosRosario Porto OrtegaMarta DarribaElectrónicaFala de EstremaduraLingua éuscaraMickey Mouse ClubhouseDepartamento de ApurímacJorge Cuña CasasbellasFrancisco Fernández del RiegoLista de nomes masculinos en galegoLalínProvincia de Ourense🡆 More