Interpretación del patrón de diseño singleton

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

único

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

Supongo que te gusta

Origin blog.csdn.net/xufei5789651/article/details/79599183
Recomendado
Clasificación