Este artigo contén variasligazóns externas e/ou bibliografía ao fin da páxina, mais poucas ou ningunha referencia no corpo do texto. Por favor,mellora o artigo introducindonotas ao pé,citando as fontes. Podes ver exemplos de como se fainestes artigos. |
![]() | Este artigo ou sección precisa dunha revisión do formato que siga olibro de estilo da Galipedia. Pode axudar amellorar este artigo e outros encondicións semellantes. |
![]() | Este artigo ou sección precisa dunha revisión ortográfica e/ou de gramática(recurso útil:corrector ortográfico en liña de galego). Podes axudarte dorevisor ortográfico, activándoo en:Preferencias →Trebellos →Navegación → ![]() Colabora connosconeste artigo e noutros encondicións semellantes para que a Galipedia mellore e medre. |
Enenxeñaría de software, opadrón de deseñoSingleton (Instancia Única) emprégase para garantir que unhaclase 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.
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.
O uso do padrón é axeitado cando:
Os clientes acceden á instancia do Singleton a través da operación definida con esa finalidade.
As principaisvantaxes do padrón Singleton son:
Á hora de utilizar o padrón Singleton, débense ter en conta algúns aspectos de implementación, entre os que destacan:
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, enJava pódese definir a operación de clase mediante un método estáticoobterInstancia()
da claseSingleton
, que tamén define unha variable estática_instancia
que contén a súa única instancia.
publicclassSingleton{privatestaticSingleton_instancia=null;privateSingleton(){}publicstaticsynchronizedSingletonobterInstancia(){if(_instancia==null){_instancia=newSingleton();}return_instancia;}}
Os clientes acceden ao Singleton exclusivamente a través do métodoobterInstancia()
. A variable_instancia
inicialízase anull
e o método estáticoobterInstancia()
devolve o seu valor, inicializándoa coa única instancia en caso de que sexanull
.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 deSingleton
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 tipoSingleton
, o métodoobterInstancia()
pode asignar a esta variable unha instancia dunha subclase deSingleton
.
Nótese o uso desynchronized
para permitir a súa utilización enaplicació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 deexclusió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.
publicclassSingleton{privatestaticSingleton_instancia=newSingleton();privateSingleton(){}publicstaticSingletonobterInstancia(){return_instancia;}}
Este método ten varias vantaxes:
synchronized
no métodoobterInstancia()
.Porén, tamén ten algúns inconvenientes. Destaca principalmente:
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ónobterInstancia()
deSingleton
.
Outra maneira de elixir a subclase deSingleton
é trasladar a implementación deobterInstancia()
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 unrexistro de obxectos Singleton. Así, en lugar de que sexaobterInstancia()
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. CandoobterInstancia()
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.
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áboaasociativa).
classMain{staticvoidbuscar(){// 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.Dicionariod=Dicionario.instancia();System.out.println("O valor asociado a can é "+d.buscar("can"));System.out.println("O valor asociado a oso é "+d.buscar("oso"));}staticvoidengadir(){Dicionariod=Dicionario.instancia();d.engadir("gato","cat");d.engadir("can","dog");d.engadir("rato","mouse");d.engadir("oso","bear");d.engadir("león","lyon");}staticpublicvoidmain(Stringargv[]){engadir();buscar();}}classDicionario{// A clase Singleton garda un atributo de clase, normalmente privado, que// mantén a referencia coa única instancia da clase.staticprivateDicionario_instancia;// Estado privado asociado coa instancia única.privateHashtable_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.privateDicionario(){_taboa=newHashtable();}// 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.staticDicionarioinstancia(){if(_instancia==null){_instancia=newDicionario();}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.publicvoidengadir(Stringclave,Stringvalor){_taboa.put(clave,valor);}publicStringbuscar(Stringclave){return(String)_taboa.get(clave);}}
![]() | Commons ten máis contidos multimedia sobre: Singleton |