Programação orientada a abstração

Olá,

Tenho uma dúvida sobre orientação a objetos na prática, principalmente com interface.

Por exemplo,

Suponha que eu tenha o seguinte cenário.

 public abstract class Funcionario {
       private Double salario;

       public abstract void calculaBonificacao();

       public Double getSalario() {
            return salario;
    }

    public void setSalario(Double salario) {
            this.salario = salario;
      } 


      }


      class Gerente extends Funcionario{

            @Override
            public void calculaBonificacao() {
                	// implementacao
            }

        }

        class Vendedor extends Funcionario{

          @Override
          public void calculaBonificacao() {
          	// implementacao
	
        }

       }

Neste caso o que eu teria ?

       class FuncionarioBO {
               private FuncionarioRepository repository;

            public  void calcularSalario(Funcionario funcionario){
                funcionario.calculaBonificacao();
             repository.salvar(funcionario);
                }

      }

Mas na prática a arquitetura mais comum é as regras de negócio ficarem centralizadas no Objeto de negócio. Neste exemplo dei não vejo como poderia salvar o estado do objeto já que acredito que o Hibernate não entenderia isso e daria erro, correto ?

Uma outra situação seria um outro método que recebe alguém que implementa uma interface e tem que salvar esse objeto de forma polimórfica.

Alguém sabe tirar essas dúvidas minhas ? Tenho muito mais dúvidas relacionadas ao assunto, mas a explicação disso já me daria um norte.

Alguém ?

apenas uma correção vc não criou uma interface, vc criou uma classe abstrata, para criar interface é assim:

public interface Funcionario {
    
}

agora um artigo q vc pode estar lendo pra entender melhor é:
https://www.devmedia.com.br/interfaces-x-classes-abstratas/13337

Desculpe, mas talvez o nome do tópico tenha te levado a interpretar errado a pergunta. Mudei para "programação orientada a abstração " . Neste exemplo funcionário é uma classe abstrata, mas a minha dúvida é sobre salvar o estado de objeto objetos abstratos ou interfaces .

O hibernate “olha” para o objeto e o compara ao mapeamento disposto.
Ao “olhar” o objeto, o mecanismo do hibernate identifica o que pode ou não ser persistido (transient, por exemplo), valida se o mesmo está no grupo de entidades mapeadas (em um arquivo .hbm.xml ou anotado como @Entity) e faz a validação com a tabela específica (pelo nome da classe ou pela anotação @Table), verifica as colunas, PK, FK, uniques, constraints e etc e, só então, permite que você realize operações (como insert, update, etc).
Logo, o que conta, para o hibernate, é como o mapeamento está e como o objeto é aderente a ele.

1 curtida

Então você está dizendo que se a instância que for passada para a classe Funcionario for instancia de Gerente o Hibernate consiguira persistir perfeitamente porque ele vai buscar se a instancia desse objeto esta mapeada ? Ou seja, se eu chamar funcionarioBO.calcularSalrio(new Gerente()); o hibernate conseguira persistir o objeto na Tabela correta se Gerente estiver mapeado corretamente ?

Mas como isso seria se por exemplo :

      interface Historico{} 
       @Entity
       class HistoricoA implements Historico{}
       @Entity
       class HistoricoB implements Historico{}

        class HistoricoBO {
               HistoricoRepository repository;
               
             public void manipulaEGravaEstado(Historico historico){
                         //historico.alguma coisa aqui
                         repository.salvar(historico);
               }
        }

Um método no BO que recebe alguém que implementa determinada interface, executa alguma operação e então grava o estado do objeto na tabela correta.

Entendeu ?

Depende de qual foi a forma que você mapeou e qual estratégia está utilizando para a herança (single table ou não).
Mas, teoricamente, sim, o hibernate vai olhar o mapeamento, vai identificar o tipo do objeto e comparar com o que foi definido no mapeamento,
Basicamente, é isso.

Aqui temos duas coisas:

  • Os atributos do objeto e seus respectivos valroes
  • O estado do objeto

Creio que você esteja confundindo isso.
Quando falamos em ORM, como hibernate, não falamos em salvar o estado do objeto em si, isso seria responsabilidade de um mecanismo de serialização e o objeto deveria ser de uma classe que estende a interface Serializable.
A função específica do hibernate é pegar os atributos (na verdade, a referência de cada atributo e o valor dado a cada um deles) e, baseado no mapeamento definido, persistir, realizar select, update, insert e delete. Ele não usa o objeto como todo, mas, a parte mapeada do mesmo (e não transient)

Correto, mas nesse exemplo que lhe dei HistoricoRepository repository; Funcionaria corretamente e conseguiria salvar de forma dinâmica o objeto no banco de dados ?
Porque pelo menos nos Spring Data Jpa ao criar a seguinte classe :

        public interface HitoricoRepository extends JpaRepository<Historico, Long> {}

Ocorre um erro dizendo que a Historico não está mapeado (e realmente não está, é uma interface). Ou seja, para resolver isso acredito que deva ter um HistoricoARepository e um HistoricoBRepository para suas respectivas classes. Ou seja, dessa maneira imagino o método historicoBo.manipulaEGravaEstado(new HistoricoA()); contendo uma implementação contendo um

    if(historico instanceof HistoricoA){
      historicoABO.salvar(historico);
   }else if(historico instanceof HistoricoB){
       historicoBBO.salvar(historico);
    }

Quero evitar essa verificação algo mais ou menos nesse sentido.

        public interface HitoricoRepository extends JpaRepository<Historico, Long> {}

Interfaces definem comportamentos comuns, não definem atributos comuns, logo, tentar persistir um elemento a partir da comparação de tipo com uma interface, não e´um caminho adequado a se seguir.
É cabível, porém, que você tenha algo como

@Entity
public class Foo implements Serializable {}

Por exemplo.
Agora, se você tem a intenção de ter um HistoricoA e HistoricoB, primeiro precisa ter certeza que precisa destas duas classes. Segundo, se ambos são históricos você pode criar uma classe, mesmo abstrata, Historico e fazer com que HistoricoA e HistoricoB estendam desta classe.

@MappedSuperclass
public abstract class Historico {}

@Entity
public HistoricoA extends Historico{}

@Entity
public HistoricoB extends Historico{}

Aí faz sentido, pelo menos, para mim.

Suponha que Historico/Relatorio seja uma interface define um comportamento em comum, e a regra fosse essa ou algo parecido com isso. O histórico foi um exemplo. Se esse cenário que fosse exposto fosse um cenário real, como seria ? Seria da maneira como expus mesmo ?

        @MappedSuperclass public abstract class ClasseQualquer{}

O que você precisa observar, antes de qualquer coisa, é que um framework, seja qual for, é desenvolvido com o objetivo de atender ao que existe de mais corriqueiro.
Sendo assim, o hibernate pode não atender a todas as situações que existem ou que você venha a encontrar.
Volto a tecla que: apenas se o objeto vier de uma classe mapeada é que ele será persistido pelo hibernate. Qualquer coisa fora disso, não funciona.
Como não é possível mapear interfaces, logo, você nunca conseguirá tratar um cenário em que o objeto a ser persistido “é um” elemento daquela interface. Lógico, isso de acordo com o que eu conheço. Pode haver alguma maneira, mas, eu desconheço.

1 curtida