2011-11-02 4 views
7

J'ai donc quelques classes 'Manager', par exemple GroupManager. Tous ces gestionnaires sont des singletons.Génériques Java, singletons et méthodes statiques

En utilisant cette méthode pour instanciation:

private static GroupManager groupManager = null; 

private GroupManager() 
{ 

} 

public static GroupManager Instance() 
{ 
    if (groupManager == null) 
    { 
     groupManager = new GroupManager(); 
    } 
    return groupManager; 
} 

Je pense que je devrais commencer à utiliser un héritage qu'ils ont beaucoup de méthodes copiées.

Les méthodes Instance() pour chaque gestionnaire sont les mêmes.

Donc, pour l'héritage que je peux le faire (évidemment):

GroupManager extends Manager 

Est-il possible d'utiliser les médicaments génériques d'utiliser la même méthode d'instance pour tous les gestionnaires, quelque chose comme:

public class Manager<E> 
{ 
    private static E instance = null; 

    public static E Instance() 
    { 
     if (instance == null) 
     { 
      instance = new E(); 
     } 
     return instance; 
    } 

} 

Je pense cela a du sens :)

Alors vous feriez GroupManager.Instance() comme d'habitude.

+1

Java Generics ne sont en aucune façon la Identique aux modèles C++! Laisser aller! Vous ne pouvez jamais allouer un objet (c'est-à-dire appeler nouveau) en utilisant un Java Generic. Essayez une recherche google pour "Java Type Erasure" – DwB

+0

Connexes: http://stackoverflow.com/questions/1927789/why-should-i-care-that-java-doesnt-have-reified-generics – BalusC

+0

Manager E est un référence à un type générique. Il n'y a pas de moyen simple de configurer une classe pour allouer des objets d'un type qui n'est connu que lors de l'exécution. La réponse de Reid Mac est ce que j'essaierais. – DwB

Répondre

9

Vous ne comprenez pas comment fonctionnent les génériques et les statistiques. Si vous avez un champ ou une méthode statique (comme "instance" ou instance()), qui peut être appelé sans instancier le gestionnaire de classes, comment voulez-vous que la JVM (et le compilateur pair) sache quel type E est supposé être?

Voici un exemple, selon la suggestion de G_H:

GeneralManager et AreaManager à la fois étendre directeur

La classe Manager est le seul qui a la méthode statique getInstance():

public class Manager { 

     private static Map<Class<? extends Manager>,Manager> INSTANCES_MAP = new java.util.HashMap<Class<? extends Manager>, Manager>(); 

//Also, you will want to make this method synchronized if your application is multithreaded, 
//otherwise you mihgt have a race condition in which multiple threads will trick it into 
//creating multiple instances 
     public static <E extends Manager> E getInstance(Class<E> instanceClass) throws InstantiationException, IllegalAccessException { 
      if(INSTANCES_MAP.containsKey(instanceClass)) { 
       return (E) INSTANCES_MAP.get(instanceClass); 
      } else { 
       E instance = instanceClass.newInstance(); 
       INSTANCES_MAP.put(instanceClass, instance); 
       return instance; 
      } 
     } 
    } 
+1

Oui, mais ça ne marchera pas du tout pour l'idée d'implémenter des singletons. Vous auriez besoin d'une structure horriblement déformée comme une carte de 'Class'es à instances. –

+0

+1, c'est très vrai, je pensais que je devrais ajouter cette observation aussi bien ou pas (j'ai décidé de ne pas faire croire que les notions de base des génériques et de la statique doivent d'abord être comprises avant d'être utilisées comme ça). Cependant vous faites un bon point. De plus, vous pouvez restreindre le type E générique à une classe de base comme E extends RootOfIheritanceChainClass. –

+0

Je suis un peu perdu lol, devrais-je juste aller avec: fondamentalement, j'ai besoin d'une nouvelle méthode Instance() pour chaque nouveau gestionnaire. – Metalstorm

2

Non, ça ne va pas marcher. Java utilise des génériques lors de la compilation pour la vérification de type, mais ne génère pas de classes supplémentaires et ne conserve pas d'informations sur les paramètres de type lors de l'exécution.

Lorsque vous déclarez Manager<E> avec ce paramètre de type E, cela ne joue qu'un rôle dans une instance réelle. Vous pourriez avoir une sous-classe comme GroupManager extends Manager<String> ou quoi que ce soit, mais ce n'est pas magique va générer une variété de la méthode statique.

Les méthodes statiques et les membres appartiennent à une classe et non à une instance. Donc essayer d'utiliser des génériques là-bas, qui sont destinés à saisir des instances, ne va pas voler.

0

Si vous créez votre classe de gestionnaire de groupe comme suit, vous pouvez appeler votre méthode d'instance.

public class GroupManager extends Manager<GroupManager>{} 

Et dans votre classe Manager essayez ceci ...

public class Manager<E> 
{ 
private static E instance = null; 

public static E Instance() 
{ 
        try { 
      return instance.newInstance(); 
     } catch (InstantiationException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } catch (IllegalAccessException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 

     return null; 
} 

Ou si vous connaissez l'objet que vous voulez une instance pour, il suffit de faire la méthode générique

public static <T> T getInstance(Class<T> t){ 
      try { 
      return t.newInstance(); 
     } catch (InstantiationException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } catch (IllegalAccessException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 

     return null; 
    } 

I HAVN N'a pas essayé tout ça, donc je ne sais pas si ça va marcher.

+1

le premier exemple est faux – Fabian

0

Injecter le constructeur dans un contexte générique.Cash est pas sûre, mais il est utilisé que dans le contexte statique de sorte que son bien si vous ne manquez pas l'utiliser

public class Example { 

    public static class MySingletonClass { 
    } 

    public interface Provider<T> { 
     T get(); 
    } 

    static final Provider<MySingletonClass> myClassInstanceProvider = new Cash<MySingletonClass>(new Provider<MySingletonClass>() { 
      @Override 
      public MySingletonClass get() { 
       return new MySingletonClass(); 
      } 
     }); 


    public static class Cash<T> implements Provider<T> { 
     private Provider<T> provider; 

     public Cash(Provider<T> provider) { 
      this.provider = provider; 
     } 

     @Override 
     public T get() { 

      final T t = provider.get(); 
      provider = new Provider<T>() { 

       @Override 
       public T get() { 
        return t; 
       } 
      }; 
      return t; 
     } 
    } 
} 
0

public class Manager<E>{ 

private static Object instance = null; 

    public static E Instance() { 
     if (instance == null) 
     { 
     instance = new E(); 
     } 
     return (E)instance; 
    } 
} 

+0

La réponse ci-dessus va faire, n'est-ce pas? –

+0

ce ne fonctionne pas – Fabian

+0

qui ne fonctionne pas ... – mahieddine