Implementación en C# del patrón de diseño Singleton
Modo singleton El modo singleton (traducido como singleton o estado único) es un modo relativamente simple y de uso común en patrones de diseño. A veces, se requiere que una determinada clase tenga solo una instancia en toda la aplicación. En este caso, puede Diseñar usando el patrón Singleton. Las clases diseñadas usando el patrón Singleton no solo garantizan que solo haya una instancia en la aplicación, sino que también proporcionan un método variable no global para el acceso global, llamado punto de acceso global. es un lenguaje puro orientado a objetos que no tiene el concepto de variables globales. Se dice que es muy conveniente, como C #. Este artículo utiliza un ejemplo de contador para describir cómo usar el modo Singleton en C #. Diseñado como una variable miembro privada de la clase de contador, que es leída y escrita por diferentes subprocesos para garantizar la precisión del recuento. En toda la aplicación, la instancia de la clase de contador debe ser la única implementación de Singleton. los dos métodos de la implementación estándar de Singleton en los libros de texto. El siguiente es un método de pseudocódigo similar a C#: utiliza System; namespace csPattern Singleton { public class Singleton { static Singleton uniSingleton = new private Singleton() {} static public Singleton. instancia() { return uniSingleton; } } } Método 2 usando el espacio de nombres csPattern Singleton { clase pública Singleton { static Singleton uniSingleton () {} instancia pública estática Singleton () { if (null == uniSingleton) { uniSingleton = new Singleton _lazy(); } return uniSingleton; } } } Hay dos técnicas para implementar el patrón Singleton. Una es usar variables miembro estáticas para guardar instancias globales. Para garantizar la unicidad, use el método de miembro estático instancia() en lugar de. nueva palabra clave para obtener una instancia de la clase para lograr un efecto visible globalmente. La segunda es establecer el método de construcción en privado. Si se usa la nueva palabra clave para crear una instancia de la clase, se informará un error durante la compilación para evitarlo. ¿Un error tipográfico? El método de inicialización del método dos anterior se llama inicialización diferida. Crea una instancia de la clase cuando se necesita una instancia por primera vez. usado o no, en comparación con el método dos, ahorra recursos del sistema. Sin embargo, este método ahorra recursos del sistema. 2. En aplicaciones de subprocesos múltiples, a veces ocurren múltiples instancias. Supongamos que hay un subproceso principal y el subproceso puede encontrar algunas razones para bloquearse. durante un período de tiempo al crear una instancia de la clase (como la velocidad de la red o la necesidad de esperar a que se procese algo). Liberación de los recursos utilizados. La situación de ejecución en este momento es la siguiente. () para intentar obtener una instancia de la clase. El método miembro instancia() determina que la clase no ha creado una instancia única, por lo que comienza a crear una instancia. Debido a algunos factores, el hilo principal no puede crear con éxito de inmediato. Debe esperar un tiempo. En este momento, el hilo también llama a la instancia () para intentar obtener una instancia de la clase. Debido a que el hilo principal no ha creado correctamente la instancia en este momento, el hilo comienza a crear. Una nueva instancia. El resultado es que los dos subprocesos crearon dos instancias respectivamente para la clase de contador, lo que hará que se restablezca el valor de recuento, lo que va en contra de la intención original de Singleton. La forma de resolver este problema es sincronizar. Echemos un vistazo al método de implementación del ejemplo del contador en este artículo: usar System usando System Threading;
space csPattern Singleton { public class Counter { static Counter uniCounter = new Counter(); // Instancia única de almacenamiento private int totNum = ; // Valor de recuento de almacenamiento private Counter() { Thread Sleep( ); se retrasan debido a factores // no afectará el recuento sin una inicialización diferida } static public Counterstance() { return uniCounter } public void Inc() { totNum ++;} // Count plus public int GetCounter() { return totNum; ;} //Obtener el valor de conteo actual} } El siguiente es el programa cliente que llama a la clase Contador. Aquí definimos cuatro subprocesos para usar el contador al mismo tiempo. Cada subproceso lo usa veces. Sistema; usando System IO; usando System Threading csPattern Singleton MutileThread { public class MutileClient { public MutileClient() {} public void DoSomeWork() { Counter myCounter = Counter instancia(); (); //Método 2 for (int i = ; i < ; i++) { myCounter Inc(); Consola WriteLine( Thread { } informa: El contador actual es: { } Thread CurrentThread Name ToString() myCounter GetCounter() ToString ()); } } public void ClientMain() { Hilo hilo = Hilo Nombre hilo = Hilo hilo = nuevo Hilo (nuevo Hilo Inicio)); (este DoSomeWork)); Nombre del hilo = Thread Thread Start() hilo Start(); /El hilo también solo ejecuta el mismo trabajo que otros hilos} } } La siguiente es la entrada de prueba de este programa para la función Main usando System; namespace csPattern Singleton { public class RunMain { public RunMain() {} static public void Main(string) [] argumentos) { MutileThread MutileClien
t myClient = new MutileThread MutileClient(); myClient ClientMain(); Consola del sistema ReadLine(); los resultados de la ejecución son los siguientes: Informe de subproceso: El contador actual es: Informe de subproceso: El contador actual es: Informe de subproceso : El contador actual es: Subproceso Informe de subproceso: El contador actual es: Subproceso Informe de subproceso: El contador actual es: Subproceso Informe de subproceso: El contador actual es: Subproceso Informe de subproceso: El contador actual es: Subproceso Informe de subproceso: El contador actual es : Hilo Informe de hilo: El contador actual es: Hilo Informe de hilo: El contador actual es: Hilo Informe de hilo: El contador actual es: Hilo Informe de hilo: El contador actual es: Hilo Informe de hilo: El contador actual es: Hilo Informe de hilo: El contador actual es: Informe de subproceso: El contador actual es: Informe de subproceso: El contador actual es: Debido a la diferente programación de subprocesos del sistema, el resultado de la ejecución es diferente cada vez, pero el resultado final debe estar en el método uno. La instancia se crea al principio, el método instancia () no necesita juzgar si ya existe una instancia única y devolverla, por lo que no habrá problemas de múltiples instancias de la clase de contador usando el método 2. Subprocesamiento del sistema; utilizando System Runtime CompilerServices; espacio de nombres csPattern Singleton { public class Counter_lazy { static Counter_lazy uniCounter; private int totNum = private Counter_lazy() { Thread Sleep( ); MethodImpl(MethodImplOptions Synchronized)] // El atributo de sincronización del método static public Counter_lazy instancia() { if (null == uniCounter) { uniCounter = new Counter_lazy() } return uniCounter } public void Inc() { totNum ++; ;} public int GetCounter() { return totNum;} } } Me pregunto si ha notado que la declaración [MethodImpl(MethodImplOptions Synchronized) encima del método instancia()) es el punto clave de la sincronización. Especifica que la instancia(). El método solo puede ser utilizado por un subproceso a la vez. Esto evita que el subproceso llame a la instancia () antes de que se cree la instancia y el subproceso intente obtener la instancia. De acuerdo con los consejos de MSDN. También puede usar la palabra clave lock para bloquear el subproceso. El código es el siguiente: usando System; usando System Threading; namespace csPattern Singleton { public class Counter_lazy { static Counter_lazy uniCounter;
myObject = new object(); private int totNum = ; private Counter_lazy() { Thread Sleep( ); //Asume bloques de subprocesos múltiples durante milisegundos por algún motivo} static public Counter_lazy event() { lock(myObject) { if ( null == uniCounter) { uniCounter = new Counter_lazy(); } return uniCounter; } } public void Inc() { totNum ++;} public int GetCounter() { return totNum;} } } Lock() es para agregar el bloqueo mutex Solo permite que un subproceso acceda al bloque de instrucciones entre llaves después de él. No se desbloquea hasta que se ejecuta el código del bloque de instrucciones. Después del desbloqueo, otros subprocesos pueden ejecutar su bloque de instrucciones. para la definición de sincronización private static Mutex mut = new Mutex(); y luego modifique instancia() de la siguiente manera para obtener el resultado correcto static public Counter_lazy instancia() { mut WaitOne(); if (null == uniCounter) { uniCounter = new Counter_lazy; (); } mut ReleaseMutex(); return uniCounter; } Tenga en cuenta que en este ejemplo, cuando utiliza el método 2, debe cambiar el programa cliente del método 1. Elimine la anotación de Counter_lazy intance() y anote Counter intance(). El modo singleton también se puede expandir y limitar a una determinada aplicación con ligeras modificaciones. Solo se permite la existencia de m instancias y se proporcionan métodos de acceso globalmente transparentes para m instancias lishixinzhi/Article/program/net/201311/12545