Foro de elhacker.net

Programación => Java => Mensaje iniciado por: CaTZ en 14 Enero 2015, 16:04 pm



Título: Unificar código en clase abstracta
Publicado por: CaTZ en 14 Enero 2015, 16:04 pm
Buenas tardes,

Tengo un problemilla con un tema y creo que es porque no tengo claro algunos conceptos.

Lo que tengo que hacer es unificar el código idéntico de 2 clases en otra clase abstracta para evitar duplicar el código.

Suponiendo que en Class1 y en Class2 hay 2 métodos (Metodo1 y Metodo2) que comparten código, sería meter ese código en una tercera clase abstracta (AbstractClass) para unificar el código y así cuando haya que modificar algo sólo se modifique en un sitio. El problema que tengo es que no se cómo tengo que llamar a los métodos de la clase abstracta desde las otras clases ya que yo tenía entendido que en la clase abstracta sólo se ponía el método (sin implementar código) y desde cada clase se controlaba el comportamiento.

Pues bien...yo he pensado en esto (de forma resumida):

AbstractClass
Código:
public abstract class AbstractClass{
              public boolean Metodo1 {
                    bla bla bla bla......
                    return true;
              }
              public boolean Metodo2 {
                    bla bla bla bla......
                    return false;
              }
}

Class1
Código:
public class Class1 extends AbstractClass{
              public boolean Metodo1();
              public boolean Metodo2();
}

Class2
Código:
public  Class2 extends AbstractClass{
              public boolean Metodo1();
              public boolean Metodo2();
}

¿Cómo debería hacerlo?

Muchas gracias de antemano!


Título: Re: Unificar código en clase abstracta
Publicado por: iGust4v0x en 14 Enero 2015, 18:28 pm
Se supone que si extiendes 2 clases de una sola, es porque ambas clases necesitan de los métodos y/o propiedades de la clase padre (sea abstracta o no). Además, puedes sobreescribir dichos métodos para aplicar polimorfismo.

Antes que nada un ejemplo:

Código
  1. public interface Animal {
  2.  
  3.    String name();
  4.    void setName(String name);
  5.    void doSomething();
  6.    String description();
  7. }

Código
  1. public abstract class AnimalImpl implements Animal {
  2.  
  3.    private String name;
  4.  
  5.    public AnimalImpl(String name) {
  6.        this.name = name;
  7.    }
  8.  
  9.    @Override
  10.    public String getName() {
  11.        return name;
  12.    }
  13.  
  14.    @Override
  15.    public void setName(String name) {
  16.        this.name = name;
  17.    }
  18.  
  19.    @Override
  20.    public void doSomething();
  21.  
  22.    @Override
  23.    public String description();
  24.  
  25. }
  26.  

Código
  1. public class Dog extends AnimalImpl {
  2.  
  3.    public Dog(String name) {
  4.        super(name);
  5.    }
  6.  
  7.    @Override
  8.    public void doSomething() {
  9.        System.out.println("Guarf Guarf Guarf!");
  10.    }
  11.  
  12.    @Override
  13.    public String description() {
  14.        return "perro";
  15.    }
  16.  
  17. }

Código
  1. public class Cat extends AnimalImpl {
  2.  
  3.    public Cat(String name) {
  4.        super(name);
  5.    }
  6.  
  7.    @Override
  8.    public void doSomething() {
  9.        System.out.println("Miau maiu miaauuu");
  10.    }
  11.  
  12.    @Override
  13.    public String description() {
  14.        return "gato";
  15.    }
  16.  
  17. }

Código
  1. public class Owner {
  2.  
  3.    String name;
  4.    Animal pet;
  5.  
  6.    public Owner() {}
  7.  
  8.    public Owner(String name, Animal pet) {
  9.        this.name = name;
  10.        this.pet = pet;
  11.    }
  12.  
  13.    public String getName() {
  14.        return name;
  15.    }
  16.  
  17.    public void setName(String name) {
  18.        this.name = name;
  19.    }
  20.  
  21.    public Animal getPet() {
  22.        return pet;
  23.    }
  24.  
  25.    public void setPet(Animal pet) {
  26.        this.pet = pet;
  27.    }
  28.  
  29.    @Override
  30.    public String toString() {
  31.        return "Hola, mi nombre es "+name+", mi mascota se llama "+pet.getName()+" y es un "+pet.getDescription()+
  32.        ".\n"+pet.doSomething();
  33.    }
  34. }

Código
  1. public class Main {
  2.    public static void main(String[] args) {
  3.        Animal bobby = new Dog("Bobby");
  4.        Animal minina = new Cat("Minina");
  5.  
  6.        Owner guillermo = new Owner("Guillermo", bobby);
  7.        Owner vilma = new Owner("Vilma", minina);
  8.  
  9.        System.out.println(guillermo); // la llamada a toString() es implícita
  10.        System.out.println(vilma);
  11.    }
  12. }

Citar
Output:
Hola, mi nombre es Guillermo, mi mascota se llama Bobby y es un perro.
Guarf Guarf Guarf!

Hola, mi nombre es Vilma, mi mascota se llama Minina y es un gato.
Miau miau miaauuu

Respecto a tu pregunta, si ambos comparten código, el código compartido debería estar en la clase padre. Recuerda, que en una clase abstracta, a diferencia de las interfaces, sí se pueden implementar métodos.


Saludos.


Título: Re: Unificar código en clase abstracta
Publicado por: JonaLamper en 15 Enero 2015, 00:29 am
Sería más o menos así:

Clase MiClaseAbstracta (clase padre con dos métodos abstractos):
Código
  1. public abstract class MiClaseAbstracta {
  2.   public abstract int Metodo1 ();
  3.   public abstract int Metodo2 ();
  4. }

Clase MiClase1 (clase hijo que debe implementar los dos métodos abstractos de la clase padre):
Código
  1. public class MiClase1 extends MiClaseAbstracta {
  2.   public int Metodo1 () {
  3.      return this.numero1;
  4.   }
  5.   public int Metodo2 () {
  6.      return this.numero2;  
  7.  }
  8.  
  9. }

Clase MiClase2 (clase hijo que debe implementar los dos métodos abstractos de la clase padre):
Código
  1. public class MiClase2 extends MiClaseAbstracta {
  2.   public int Metodo1 () {
  3.      return this.numero3;
  4.   }
  5.   public int Metodo2 () {
  6.      return this.numero4;  
  7.   }
  8. }



La jerarquía es esta:

                                                          MiClaseAbstracta
                                                                     |      
                                                                     |
                                                            _____ | _____
                                                            |                  |      
                                                            |                  |      
                                                     MiClase1        MiClase2

          
Es decir, digamos que en tu clase abstracta (que actúa como padre) te declaras los métodos abstractos. Y las subclases que estén por debajo, deben implementar dichos métodos (es obligatorio que implementen todos los métodos abstractos de la clase padre). Además de esto, la clase padre también puede tener sus propios métodos implementados (a los cuales las clases hijos podrán tener acceso).


Título: Re: Unificar código en clase abstracta
Publicado por: CaTZ en 15 Enero 2015, 09:35 am
Muchas gracias a los 2 por vuestras respuestas.

Yo había pensado hacer lo de JonaLamper pero es que en mi caso el Metodo1 y el Metodo2 son exactamente iguales para la Clase1 y Clase2, por eso tengo que implementar ambos métodos en la clase padre (ClaseAbstracta), pero el caso es:

¿Cómo llamo al método desde la clase hija?¿Simplemente poniendo el nombre?

Mi clase abstracta sería esta:

Código:
public abstract class MiClaseAbstracta {
     public void Metodo1 () {
         return this.numero1;
     }

     public void Metodo2 () {
         return this.numero2;
     }
}

Y por ejemplo mi Clase1 sería:

Código:
public class MiClase1 extends MiClaseAbstracta {
     //¿Aquí como llamo al Metodo1 y Metodo2?
}

Muchas gracias!


Título: Re: Unificar código en clase abstracta
Publicado por: JonaLamper en 15 Enero 2015, 11:47 am
Se llaman exactamente igual que si estuvieran en la Clase1 o la Clase2.

Cuando hay herencia, los métodos y atributos de la clase padre se heredan a todos sus hijos (como si dichos métodos estuvieran declarados en los hijos).

Luego también depende de la visibilidad que tengas en esos métodos o atributos (public, protected o private), pero si son públicos no hay problema.

Una posible llamada sería esta:


Código
  1. public class MiClase1 extends MiClaseAbstracta {
  2.     //Supongamos que en MiClase1 tengo un atributo que quiero que tome el valor que me devuelve el Metodo1 (que es de tipo int)
  3.      private int MiNumero;
  4.  
  5.      this.MiNumero = Metodo1();
  6. }



Nota: hay una cosa que está mal (aunque directamente no influya en entender este concepto). Para poner el ejemplo te he puesto que los métodos eran de tipo void, y los métodos de tipo void no devuelven ningún valor. Así que imagina que en vez de ser tipo void son de tipo int (es decir, me devuelven un valor de tipo int). Te lo he cambiado en el ejemplo de arriba.


Título: Re: Unificar código en clase abstracta
Publicado por: CaTZ en 15 Enero 2015, 12:24 pm
Buenas JonaLamper,

No se por qué pero de esa forma no me sale el método de la clase padre. ¿Sería lo mismo esto?

...
....
this.MiNumero = super.Metodo1();



Título: Re: Unificar código en clase abstracta
Publicado por: JonaLamper en 15 Enero 2015, 12:39 pm
Disculpa, el atributo debería estar en la clase padre  :P


Título: Re: Unificar código en clase abstracta
Publicado por: CaTZ en 15 Enero 2015, 13:04 pm
Perfecto esto ya lo tengo, gracias!

Ahora si no es mucha molestia tengo otra dudilla....

Si tengo un parámetro en la clase hija con un valor x, ¿Habría alguna manera de que la clase padre recogiera este parámetro?


Título: Re: Unificar código en clase abstracta
Publicado por: JonaLamper en 15 Enero 2015, 13:11 pm
¿Un parámetro o un atributo? ^^!


Título: Re: Unificar código en clase abstracta
Publicado por: CaTZ en 15 Enero 2015, 13:17 pm
Disculpa un atributo! se me fue! xD


Título: Re: Unificar código en clase abstracta
Publicado por: iGust4v0x en 15 Enero 2015, 13:22 pm
Teóricamente no. Una clase puede no puede recibir ningún tipo de dato de sus hijos, a no ser que instances las clases hijas en la clase padre, pero eso rompería toda lógica.

Podrías crear una tercera clase (una POJO), con sus setters y getters para guardar y obtener información. Si quieres que sólo exista una instancia de dicha clase, podrías implementarlo como un singleton; ésto es, una clase de la que solo exista una instancia que será compartida por todas las clases.

Saludos.


Título: Re: Unificar código en clase abstracta
Publicado por: CaTZ en 16 Enero 2015, 10:33 am
Muchas gracias a todos por vuestras respuestas, ya tengo todo entendido! :D