Interface or Abstract?

10

I've read a lot of content on this topic until I get to this example:

public interface Funcionario{  
      public void trabalha();  
      public void recebe(double salario);  
}


public abstract class Geek implements Funcionario{  
    public abstract void trabalha();  
    public abstract void recebe(double salario);  
    public void programa(){  
       System.out.println("import java.io.*; :) ");  
    }  
}  

public abstract class BusinessMan implements Funcionario{  
     public void trabalha(){  
         System.out.println("$$$");  
     }  
     public abstract void recebe(double salario);  
}


// programador é um geek e também um funcionário...  
public class Programador extends Geek{  
      private double salario;  
      public void trabalha(){  
           super.programa();  
      }  
      public void recebe(double salario){  
            this.salario = salario;  
      }  
}

/* analista também é um geek e um funcionário, mas que trabalha de maneira diferente ao programador*/  
public class Analista extends Geek{  
      private double salario;  
      public void trabalha(){  
           super.programa();  
           supervisionaProjeto();  
      }  
      public void recebe(double salario){  
            this.salario = salario;  
      }  
      private void supervisionaProjeto(){  
           System.out.println("Supervisiona");  
      }  
}  

public class Gerente extends BusinessMan{  
     private double salario;  
     private final double BONUS = 1000.0d;  
     public void recebe(double salario){  
         this.salario = salario + this.BONUS;  
     }  
}


public class Empresa{  
   public static void main(String[] args){  
      private Funcionario[] funcionario = new Funcionario[5];  
      funcionario[0] = new Programador();  
      funcionario[1] = new Programador();  
      funcionario[2] = new Analista();  
      funcionario[3] = new Programador();  
      funcionario[4] = new Gerente();  
      // faz alguma coisa...  
   }  
}

Source: link

I changed the interface Funcionario by a class library, and made the other classes, which before implemented, now extend it. So:

public abstract class Funcionario {
    public abstract void trabalha();
    public abstract void recebe(double salario);
}

public abstract class Geek extends Funcionario{
    @Override
    public abstract void trabalha();

    @Override
    public abstract void recebe(double salario);

    public void programa() {
        System.out.println("import java.io.*; :) ");
    }
}

public abstract class BusinesMan extends Funcionario {

    @Override
    public void trabalha() {
        System.out.println("$$$");
    }

    @Override
    public abstract void recebe(double salario);

}

There was no change at all when compiling and rolling.

My question is: Does this specific case change anything with these changes? Do you have any functionality that I will lose or win?

Note: I'm not referring to performance. I'm referring to the issue of maintenance or complexity, for example, if I later need to add any more type of employee, is there going to be a difference in both cases?

    
asked by anonymous 08.10.2014 / 21:27

3 answers

7

At first there was not much change. Interfaces are usually preferred when there is no state or implementations, which is your case. And this is the most important thing to watch. This case does not demand classes. If the problem was another I would think differently. That is why it is important to never go after good practices and analyze the specific problem. Understand what you want. For this it is important to understand the difference between the two.

You might even have a future limitation using an abstract class because Java only allows "true" inheritance of only one class. And any class that inherits from the abstract class Funcionario can not inherit from another class, it can only implement other interfaces.

In practice I doubt this really is a problem in most cases. If you only implement Funcionario in the classes described, you will in the future allow you to inherit from some class (abstract or not) since you had only implemented interfaces and no classes. But will you modify these existing classes to inherit from another class? Will it hurt the Open / Close principle ? And he is usually important in these cases. I do not say that there is no situation where this may be interesting, but it is not usually.

Is there any reason to prefer the abstract class? If I did not find one, I would have the interface. Usually the reason is that you need to state. Even if I need implementations, I do not know if it would justify it, even more so in Java 8 with default methods . Unless you need to implement "implementation details", that is, private methods.

The way Funcionario is described seems to me to be stating some features that an element that is an employee of some sort should have. What is different from saying that Funcionario contains important definitions for everyone who is an employee. It's the famous difference of being and have . Use classes when derived classes will be that, in this case, are employees. Or use interfaces when derived classes only have those characteristics, behaviors defined (but not implemented).

By name it can be tempting to find that Geek or Analista are employees and not only have employee characteristics. But the code shows something different. That's why the correct specification is important to make the right choice. Maybe you know something we do not know.

About this you can learn more about the Liskov replacement principle

(in English, as always, it's better) ( have an answer here ).

Remember that in theory it is easier to turn an interface into an abstract class if one day this is necessary than the other way around. In fact both will work and bring risks.

Really performance and other technical issues are unimportant near the engineering problem you will have. In general it is easier to add interfaces. You could have advantages in the abstract class if you want to implement or modify existing implementations in it and this is reflected automatically in the descendant classes. But this needs to be done with such care that it is always necessary to question whether it is worth it.

    
08.10.2014 / 21:46
7

Conceptually there is no difference between an interface and a purely abstract class , that is, with all abstract methods.

With respect to changes, the abstract class would implement a non-abstract method to be reused in subclasses.

In short, abstract classes help if you have a generic type (superclass) that is the basis for more specific and specialized types (subclasses).

Interfaces are better at specifying the behavior of a type. Do not think about interfaces for code reuse.

Incidentally, also be careful when using inheritance to reuse code. The price to be paid (high coupling between super and subclasses) can be very expensive. Whenever possible, give preference to delegation.

Mixed approach

You can also use interfaces and abstract classes together.

Example:

public interface Funcionario {  
      void trabalha();  
      void recebe(double salario);  
}

public abstract class FuncionarioAbstrato implements Funcionario {
    double salario;
    public abstract void recebe(double salario) {
        this.salario += salario;
    }
}

I consider this approach to be more flexible, because if there were ever any other type of employee that does not fit into your class hierarchy, just implement the interface in a completely new implementation.

Segregation of Interfaces

Another approach that may be useful in the long term is to segregate the interfaces so that the actions are more specific.

Imagine the system also counts the owner on the staff for some reason. However, the owner does not work, he just gets.

So you could have a template like this:

public interface Trabalhador {  
      void trabalha();  
}

public interface Recebedor {  
      void recebe(double salario);  
}

public abstract class RecebedorAbstrato implements Recebedor {
    double salario;
    public void recebe(double salario) {
        this.salario += salario;
    }
}

public class Programador extends RecebedorAbstrato implements Trabalhador {
    public void trabalha() {  
        System.out.println("import java.io.*; :) ");  
    }  
}

public class Dono extends RecebedorAbstrato {
    //nada além d ereceber
}

And if the difference of the Analyst is simply to do something more, it could do like this:

public class Analista extends Programador {
    public void trabalha() {  
        super.trabalha();
        System.out.println("Supervisiona");    
    }  
}

Well, it was just a few ideas. There is not necessarily a more correct modeling, it always depends on the problem.

Note: method signatures on interfaces do not need public , since methods are always always public

    
08.10.2014 / 21:59
3

Well abstract classes and interfaces are different things and intended for different uses.

The main difference is that in an abstract class you can have a mix of abstract methods that someone will have to implement to consume the class and methods already implemented. In an interface you only have method declarations.

In my understanding abstract classes should be used exactly when it is interesting to share an implementation with things to be implemented since interfaces should be used when we only want to define a communication pattern between calls.

To learn more about this link. (English)

link

    
08.10.2014 / 21:45