Implementación en C# del patrón de diseño singleton Patrón singleton El patrón singleton es un patrón de diseño simple y de uso común. A veces, toda la aplicación requiere sólo una instancia de una clase. Las clases diseñadas utilizando el patrón singleton no solo garantizan que solo haya una instancia en la aplicación, sino que también proporcionan un método de variable no global para el acceso global, que se denomina punto de acceso global. Esto es muy conveniente para lenguajes puramente orientados a objetos (como C#) que no tienen concepto de variables globales. Este artículo toma un contador como ejemplo para presentar cómo utilizar el modo singleton en C#, donde el valor de recuento está diseñado como un miembro privado de la clase de contador. Es leído y escrito por diferentes subprocesos y, para garantizar un recuento correcto, las instancias de la clase de contador deben ser únicas en toda la aplicación. Implementación Singleton Primero, veamos dos implementaciones del estándar singleton del libro de texto. El siguiente pseudocódigo es similar a C#. fuerte> usando System; espacio de nombres csPattern Singleton { clase pública Singleton { Singleton estático uniSingleton = new Singleton(); singleton privado() { } instancia de Singleton pública estática() { return uniSingleton; clase pública Singleton { static Singleton uniSingleton; private Singleton() {} instancia pública estática de Singleton() { if (null == uniSingleton) { uniSingleton = new Singleton _lazy() } return uniSingleton; el tipo de tecnología de patrón singleton. Una es usar variables miembro estáticas para guardar la instancia globalmente para garantizar la unicidad, y usar el método miembro estático instancia () en lugar de la nueva palabra clave para obtener la instancia de la clase para lograr visibilidad global. El segundo método consiste en hacer que el constructor sea privado. Si utiliza la nueva palabra clave para crear una instancia de una clase, se informará un error de compilación en caso de un error de programación. El método de inicialización del Método 2 anterior se denomina "inicialización diferida" y solo crea una instancia de la clase cuando se necesita por primera vez. El método 2 es más eficiente en recursos que el método 1 porque la instancia de la clase siempre existirá independientemente de si se usa o no. Sin embargo, en aplicaciones de subprocesos múltiples, el método 2 a veces puede generar múltiples instancias. Suponiendo que hay dos subprocesos aquí, es decir, el subproceso principal y el subproceso, la creación de instancias de clase puede bloquearse por algunas razones. Puede haber algunas razones para el bloqueo por un período de tiempo (como la velocidad de la red o la necesidad de esperar a que se liberen algunos recursos en uso. La situación es la siguiente: el hilo principal primero llama a la instancia () para intentar obtener). una instancia de la clase. El método del miembro instancia () determina que la clase no se ha creado de forma única, por lo que la instancia comienza a crearse. Debido a algunos factores, el hilo principal no puede crear la instancia de inmediato y debe esperar. un período de tiempo mientras el hilo también crea la instancia. En este momento, el hilo también llamará a instancia () para intentar obtener una instancia de la clase. Debido a que el hilo principal aún no ha creado una instancia, el hilo comienza a crear una nueva instancia. El resultado es que dos subprocesos crean dos instancias de la clase de contador respectivamente, lo que provoca que se restablezca el recuento, lo que viola la intención original de Singleton. La solución a este problema es sincronizar la clase de contador con una única instancia de la clase de contador, que no es la única instancia de la clase creada por el hilo principal, ni la única instancia de la clase.
Implementación de ejemplo de contador Uso 1 usando System; usando System Threading; { Thread Sleep( ); //esto supone un retraso de milisegundos debido a algún factor //en el caso de una inicialización no diferida el recuento no se verá afectado } sta caso no afecta el recuento } static public Counterstance() { return uniCounter; } public void Inc() { totNum ++;}//count plus public int GetCounter() { return totNum;}//Obtener el valor de recuento actual}} El siguiente es un programa cliente que llama a la clase Counter. Definimos cuatro subprocesos que usan contadores al mismo tiempo, uno para cada uno de los cuatro subprocesos. El resultado correcto debería ser usar System; usando System IO; usando System Threading; public void DoSomeWork() { Contador miContador = Contador instancia(); // método I //Contador_lazy miContador = Contador_lazy instancia() //método II for (int i = ; i < ; i++) { myCounter Inc(); WriteLine( hilo { } informe: el contador actual es: { } Nombre del hilo actual ToString() myCounter GetCounter() ToString()); public void ClientMain() { Hilo del hilo = Hilo del hilo Nombre = Hilo del hilo; = new Thread(new ThreadStart(este DoSomeWork)); Nombre del hilo = Thread Thread = new Thread(new ThreadStart(this DoSomeWork)); nombre del hilo = hilo hilo hilo = nuevo hilo (nuevo ThreadStart (este DoSomeWork));