2011-01-26 7 views
5

Contexte rapideComment décorer un objet en Java

J'ai deux listes de (grandes) POJO étant passés pour une méthode dans laquelle j'ai besoin pour garantir l'unicité dans les deux listes. La meilleure solution que je peux voir est de construire deux ensembles et de vérifier que leur intersection est vide.

Le problème

Pour le contexte de cette méthode, et cette seule méthode, je dois remplacer la méthode equals et hashcode des POJO en question.

Ce que je suis à la recherche

Cela semble être un premier candiate pour décorer les objets existants. J'ai regardé Guava's ForwardingObject mais il semble mieux adapté pour déléguer des objets qui implémentent une interface donnée ce qui n'est pas mon cas. En général, je suis à la recherche d'une solution qui ...

  1. Évite de gérer tous les champs du grand POJO (constructeurs de copie).
  2. facile à comprendre et à maintenir
  3. Évite la création d'une nouvelle classe qui étend la POJO pour le bien de celui-ci méthode
+0

Êtes-vous en train de dire que les POJOs ne mettent pas en oeuvre d'égal à égal et de hashcode pour le moment et vous ne pouvez pas les changer pour le faire? –

+0

Le motif décorateur n'a vraiment pas trop de sens sans une interface commune. L'extension de la classe est "beurk". –

+0

@Eric: Non, je suis en train de dire que les égalités et les hash-codes du POJO n'ont aucun sens pour cette méthode. Bizarre peut-être mais ce n'est pas la première fois que je voulais définir une égalité contextuelle. –

Répondre

3

Je voudrais juste aller avec un cours d'emballage.

Créez une nouvelle classe instanciée avec votre POJO dans le constructeur. Il ne copie pas le POJO, ne conserve que la référence à l'original. Puis écrivez égal et hashcode comme vous le souhaitez dans cette classe wrapper.

Quelque chose comme ceci:

public class MySpecialWrapper{ 
    private final BigPojo delegate; 

    public MySpecialWrapper(BigPojo pojo){ 
    this.delegate = pojo; 
    } 

    public int hashCode(){ 
    //insert special impl here. 
    } 

    public boolean equals(Object o){ 
    //insert special impl here. 
    } 
} 

instances Mettez de la classe wrapper dans vos jeux et utiliser pour la vérification unique. Ajoutez une méthode d'accesseur (getDelegate) si vous avez besoin d'accéder au POJO incriminé en cas d'échec.

+1

Ressemble assez à la réponse d'Eric, s'il vous plaît voir mon commentaire là aussi. –

+1

Je ne suis au courant de rien qui puisse faire ça pour vous. Cependant, comme vous pouvez le voir, c'est plutôt petit. Mettez un joli commentaire en haut pour clarifier à quoi cela sert, et vous devriez être en or. Je respecte la quête de réutilisation de ce qui est déjà défini. Mais, pour quelque chose comme ça, vous devez peser cela par rapport au temps passé dans la recherche de la réponse. – rfeak

0

Vous pouvez utiliser un proxy dynamique pour envelopper chaque élément:

class VeryBigPOJO {} 

interface PojoWrapper { 
    VeryBigPOJO getPojo(); 
} 

class MyHandler implements InvocationHandler { 
    private VeryBigPOJO ob; 

    public MyHandler(VeryBigPOJO ob) { 
     this.ob = ob; 
    } 

    public Object invoke(Object proxy, Method method, Object[] args) 
      throws Throwable { 
     if(method.getName().equals("getPojo")) 
      return ob; 
     if(method.getName().equals("equals")) 
      //calculate equals 
     if(method.getName().equals("hashCode")) 
      //calculate hashCode 
    } 
} 

envelopper ensuite vos objets dans ces proxies dynamiques:

VeryBigPOJO pojo = ...; 
PojoWrapper wrapper = Proxy.newProxyInstance(MyHandler.class.getClassLoader(), new Class[] { PojoWrapper.class}, new MyWrapper(pojo)) 

Et maintenant vous pouvez ajouter vos objets wrapper à ce HashSet.

Cependant, ne serait-il pas plus facile de construire un objet id plus petit et immuable sur le grand pojo? Ce serait certainement plus lisible.

2

Une solution simple consiste à créer une classe wrapper pour chaque classe POJO. L'encapsuleur contient une référence à l'instance POJO et définit des méthodes égales et des méthodes de hachage qui calculent leurs valeurs en fonction des champs appropriés dans le POJO. Ensuite, vous pouvez utiliser les classes Collections normales.

+0

Je commence à penser de la même façon. Cela peut être trivial, mais existe-t-il une classe wrapper prédéfinie? J'aime réutiliser ce qui existe déjà pour faciliter la compréhension et l'exhaustivité. –

+0

+1 Comme je l'ai dit, vous n'avez même pas besoin d'envelopper, vous pouvez pré-calculer la valeur 'hashCode()' et un identifiant qui sera comparé dans 'equals()'. – biziclop

+0

@Andrew: Vraiment, pour votre cas, un emballage est la solution la plus simple. Vous n'êtes pas en train de créer un délégué. Comme l'a dit @biziclop, vous pouvez calculer les valeurs dont vous avez besoin directement dans le constructeur. Et vous n'avez pas nécessairement à inclure toutes les propriétés dans vos calculs, juste ce qui est unique à l'objet. L'emballage n'a donc pas besoin d'être très complexe. Vous pouvez aller encore plus loin et implémenter l'interface Comparable et utiliser le wrapper pour le tri, si c'est utile. Assurez-vous de suivre les conseils donnés dans les rubriques 7 et 8 d'Effective Java ... –