2011-12-04 21 views
5

Tengo tres clases, un usuario abstracto y dos específicos: NormalUser que contiene una ArrayList de uno o más objetos de dirección que pueden ser diferentes (doméstico, internacional, personalizado, etc.) y luego el Clase de administrador que tiene un método que devuelve verdadero. Ambos contienen más métodos que no están relacionados entre sí.Herencia de Java y evitar el uso constante de instanceof

abstract class User{ 
    public User(String username, String pw){ 
... 

} 

public class NormalUser extends User{ 
... 
    private ArrayList<Address> addresses; 

... 

    public void addAdress(ArrayList<Address> address){ 
     addresses.addAll(address); 
} 

public class Admin extends User{ 

... 
    public boolean getIsAdmin(){ 
     return true; 
    } 
} 

Ahora en otro ramo, si hago 4 objetos de usuario así por ejemplo:

ArrayList<User> users; 

    users.add(new NormalUser("1", "pw"); 
    users.add(new NormalUser("2", "pw"); 
    users.add(new NormalUser("3", "pw"); 
    users.add(new NormalUser("4", "pw"); 
    users.add(new Admin("5", "pw")); 
    users.add(new NormalUser("6", "pw"); 

Y digo que quiero utilizar el método addAddress en NormalUser, entonces tengo que abatido el usuario specfic en usuarios a NormalUser, antes de que pueda utilizar el método addAddress en NormalUser así:

 if (user instanceof NormalUser){ 
     NormalUser normal = (NormalUser) user; 
     normal.addAddress(...) 
     } 

la razón por la que me gustaría tanto NormalUser y de administración para ser un usuario es para que pueda procesarlos juntos al iniciar sesión.

Pensé en agregar addEmail a la clase User y luego anularla en la clase NormalUser, pero tendría que hacer eso para cada método en la clase NormalUser, además Admin lo heredaría de la Usuario también, cuando no necesita esa funcionalidad.

Pregunta 1: ¿Hay una manera mejor de hacer esto que he escuchado usando instanceof es algo malo? y tendría que usar instanceof cada vez que utilizo un método que es específico de la clase NormalUser.

Quesiton 2: es una ArrayList de objeto ¿Direcciones de la mejor manera de vincular el Usuario Regular a direcciones específicas/(Objetos)?

No hay ninguna base de datos involucrada en este momento.

Así, por ejemplo, un usuario tiene 2 direcciones uno interno y otro internacional, y el usuario B solo tiene una dirección doméstica, el usuario C tiene una interna y una dirección personalizada etc.

Gracias.

PS. He buscado las publicaciones anteriores extensamente pero no he encontrado una solución. En ambos libros de Java, ambos muestran ejemplos de uso de instanceof, pero no se menciona que sea una mala práctica.

+0

En cuanto a este caso específico, me temo que no puedo decir cuál es mejor, pero no, 'instanceof' no es, por definición, algo malo. No debes abusar de él cuando el polimorfismo es más apropiado. –

+0

Relacionado con el 'instanceof': debe reconsiderar su diseño para que nunca llame a' addAddress' en un 'Usuario' básico. Solo debe llamar a dicho método cuando se encuentre en un bloque de código diseñado específicamente para 'NormalUser'. – toto2

+0

¿hay alguna buena razón para que los administradores no tengan direcciones? – soulcheck

Respuesta

3

Puede usar el Visitor pattern - un poco torpe y poco legible, pero probablemente la mejor solución para su problema.

En realidad, su solución con empujar addEmail a la clase base no es tan malo. Simplemente proporcione una implementación vacía en la base User y anule en RegularUser. Si desea verificar si la instancia dada de User admite la adición de correos electrónicos, proporcione otro método como supportsAddEmail que devuelva false de manera predeterminada y true al reemplazar addEmail.

+0

Pero, ¿no administrará el administrador la addAddress (incluso si está vacía)? – Brah

+0

Sí, esto significa que puede llamar a 'Admin.addEmail()' que no hace nada (no-op). Esa es la razón por la que sugiero 'supportsAddEmail', pero realmente no parece una buena idea. ¿No es esto exactamente lo que quieres? Agregue el correo electrónico si el usuario es 'NormalUser', no haga nada de lo contrario. –

+0

Creo que agregar 'addEmail' a la clase base es una buena idea, e inofensivo. En cuanto a su naturaleza no operativa, puede pensar que "alguien le ha dicho al objeto de administración sobre una dirección de correo electrónico, y si al administrador no le importa, que así sea". Donde se pone más feo es si necesitas poner 'getEmail()' en la clase base; en este caso, ciertas implementaciones tendrían que arrojar una excepción, que me parece fea. Si hace esto, al menos tenga un método como 'supportsGetEmail()'. Lo mejor sería si los sitios de llamadas saben qué subclase de Usuario tienen, por lo que puede agregar 'getEmail()' a NormalUser solamente. – yshavit

0

Creo que la solución más fácil es crear una lista de usuarios de clase que contendría una lista de Usuario Normal y una lista de Admin. Una instancia de la UserList de clase reemplazaría la lista original.El UserList clase podría proporcionar algunos métodos tales como:

  • usuario getUser (índice i) // implementado con las dos listas

  • removeuser de usuario (índice i) // implementado con las dos listas

  • NormalUser getNormalUser (índice i) // implementado con la lista normal de usuario
  • NormalUser removeNormalUser (índice i) // implementado con la lista de usuarios normales
  • de administración GetAdmin (índice i) // implementado con la lista de usuario de administración
  • administración removeAdmin (índice i) // en práctica con la lista de usuario admin
  • ....

Todo el código para el manejo de las listas apropiadas se encapsula en la clase UserList . Podría tener métodos que usen ambas listas o solo una, según lo que necesite hacer con los usuarios. Las clases que interactúan con UserList no sabrían si hay solo una o dos listas dentro de UserList.

+0

Gracias por la respuesta Phil, me parece una buena idea, aunque me hubiera gustado no tener que crear nuevas clases solo para mantener las listas. Soy nuevo en Java, pero si, por ejemplo, tuviera una superclase de animales, entonces una subclase de gato y perro. Si tuviera una lista de animales con perros y gatos, y quisiera llamar ladrido() a los perros, ¿entonces tendría que crear una lista de perros para hacerlo correcto? - Me parece contrario a la intuición:/ – Brah

+0

Hola. Si yo fuera usted, crearía (1) una lista para gatos y (2) una lista para perros. Considera que tienes 10000 perros y 10000 gatos. Si separa las listas, será mucho más rápido encontrar todos los perros, y luego, si tuviera una sola lista con 20000 animales mezclados. Cuando necesite llamar a un método como ladrar() solo necesita procesar la lista de perros en lugar de procesar 20 000 animales y tener que comprobar si son perros o gatos antes de llamar a ladrar(). El rendimiento debería ser mucho mejor con dos listas si tiene muchos elementos. – Phil