El patrón singleton es uno de los patrones más utilizados. Al aplicar este patrón, la clase del objeto singleton debe asegurarse de que solo exista una instancia. En muchos casos, todo el sistema solo necesita tener un objeto global, lo cual es beneficioso para coordinar el comportamiento general del sistema.
Conocimiento básico
definición
Asegúrese de que solo haya una instancia de una determinada clase, cree una instancia por sí misma y proporcione esta instancia a todo el sistema.
UML
elemento
- El constructor no está abierto al mundo exterior, generalmente privado.
- Devuelve un objeto singleton a través de un método estático o enumeración
- Asegúrese de que haya uno y solo un objeto de la clase singleton, especialmente en un entorno de subprocesos múltiples
- Asegúrese de que el objeto de clase singleton no reconstruya el objeto al deserializar
Tipos de patrones singleton
Los patrones de diseño de singleton se dividen en: estilo hambriento, estilo perezoso, clase interna estática, enumeración e implementación de contenedor
Chino hambriento
public class Singleton{
private static Singleton singleton = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return singleton;
}
}
Nota: el estilo Hungry Chinese es seguro para subprocesos, porque la instancia se creó antes de llamar al método getInstance ().
Hombre flojo
El arquetipo perezoso
public class Singleton {
private static Singleton singleton=null;
private Singleton(){}
public static Singleton getInstance() {
if (singleton== null) {
singleton= new Singleton();
}
return singleton;
}
}
Observaciones: este tipo de estilo perezoso no es seguro para los subprocesos y es probable que aparezcan varias instancias de Singleton en un entorno simultáneo.
El motivo de la inseguridad del subproceso : en el caso de alta concurrencia, un subproceso A se ejecuta en singleton = new Singleton (), pero aún no ha obtenido el objeto (la inicialización del objeto lleva tiempo), y el segundo subproceso B también se está ejecutando. ( Singleton == null) juicio, entonces el subproceso B obtiene la condición de juicio también es verdadera, así que continúe ejecutándose, el subproceso A obtiene un objeto, el subproceso B también obtiene un objeto, hay dos objetos en la memoria.
Perezoso seguro para subprocesos
- Agregar sincronización al método getInstance
public class Singleton{
private static Singleton instance;
private Singleton(){}
// 为了在多线程情况下保证单例对象唯一性,添加了synchropized关键字
public static synchropized Singleton getInstance(){
if(instance==null){
instance==new Singleton();
}
return instance;
}
}
Observaciones : Se creará una instancia de un singleton solo cuando se use, lo que ahorra recursos hasta cierto punto; es necesario instanciarlo en el tiempo cuando se carga por primera vez, y la respuesta es un poco más lenta. El mayor problema es que cada time getInstance se llama, se sincroniza. Sobrecarga de sincronización necesaria
- Bloqueo de doble verificación (DCL) ( recomendado )
public class Singleton{
private volatile static Singleton sinstance=null;
private Singleton(){}
public static Singleton getInstance(){
// 对instance进行了两次判空:第一层判断主要是为了避免不必要的同步,第二层的判断则是为了在null的情况下创建实例
if(sinstance==null){
synchropized(Singleton.class){
if(sinstance==null){
sinstance=new Singleton();
}
}
}
return sinstance;
}
}
Observaciones : La tasa de utilización de recursos es alta. Se creará una instancia del objeto singleton cuando getInstance se ejecute por primera vez, y la eficiencia es alta; la respuesta es un poco más lenta en la primera carga y ocasionalmente falla debido al modelo de memoria de Java . También hay ciertos defectos en un entorno de alta concurrencia, aunque la probabilidad de que ocurran es pequeña.
Clase interna estática
public class Singleton{
private Singleton(){}
public static Singleton getInstance(){
return SingletonHolder.sInstance;
}
// 静态内部类
private static class SingletonHolder{
private static final Singleton sInstance=new Singleton();
}
}
Nota : Cuando la clase Singleton se carga por primera vez, sInstance no se inicializará. Solo la primera llamada al método getInstance hará que se inicialice sInstance. Por lo tanto, la primera llamada al método getInstance hace que la máquina virtual agregue la clase SingletonHolder. Este método no solo puede garantizar la seguridad de los subprocesos, garantizar la unicidad del objeto singleton, sino también retrasar la instanciación del singleton.
enumerar
public enum SingletonEnum{
INSTANCE;
public void doSomething(){
// 具体操作
}
}
Observaciones : seguridad del hilo
El contenedor implementa el patrón singleton
public class SingletonManager{
private static Map<String,Object> objMap=new
HashMap<String,Object>();
pricate SingletonManager() {}
public static void registerService(String key,Object instance){
if(!objMap.containsKey(key)){
objMap.put(key);
}
}
public static Object getService(String key){
return objMap.get(key);
}
}
Observaciones : Este método puede administrar múltiples tipos de singleton y obtener operaciones a través de una interfaz unificada, lo que reduce el costo del usuario, oculta la implementación específica al usuario y reduce el grado de acoplamiento.
Pros y contras
Ventajas
-Dado que el modo singleton tiene solo una instancia en la memoria, reduce los costos de memoria, especialmente cuando un objeto necesita ser creado y destruido con frecuencia, y el rendimiento no se puede optimizar durante la creación o destrucción. Las ventajas del modo singleton son muy obvias
-debido al único El modo de ejemplo solo genera una instancia, por lo que se reduce la sobrecarga de rendimiento del sistema. Cuando la generación de un objeto requiere más recursos, como leer la configuración y generar otros objetos dependientes, puede generar directamente un único instancia cuando se inicia la aplicación.objetos de ejemplo, y luego use una forma permanente residente en la memoria para resolver
: patrón singleton para evitar la asignación múltiple de recursos, como una operación de archivo de escritura, ya que solo hay una instancia en la memoria, para evitar la misma recurso al mismo tiempo escritura de archivo
: el patrón singleton se puede configurar en el sistema de puntos de acceso global, optimización y acceso a recursos compartidos, por ejemplo, puede diseñar una clase singleton, responsable de procesar todas las tablas de mapeo de datos
inconveniente
: singleton generalmente no tienen una interfaz, es difícil expandir, expandir Además de modificar el código, básicamente no hay una segunda forma de lograrlo. Si
el objeto singleton contiene el Contexto, es fácil causar pérdidas de memoria. En este momento, debe prestar atención al contexto que se pasa al objeto singleton, es preferiblemente el contexto de la aplicación
Escena aplicable
Asegúrese de que una determinada clase tenga uno y solo un objeto en la escena para evitar generar múltiples objetos que consuman demasiados recursos, o debe haber solo uno y solo un objeto de un cierto tipo. Por ejemplo: crear un objeto consume demasiados recursos, como acceder a recursos como E / S y base de datos.
referencia
- Análisis de patrones de diseño de código fuente de Android y combate real
- Zen de los patrones de diseño