Skip to content
José Bocanegra edited this page Jul 14, 2021 · 34 revisions

La capa de lógica

En la arquitectura de capas que estamos utilizando en nuestros proyectos, la capa de lógica de la aplicación o negocio se encarga de coordinar los llamados del API REST y el acceso a la capa de persistencia. Es una capa intermedia entre la implementación de los recursos y la base de datos.

Una de sus responsabilidades es ocuparse de validar reglas de negocio o de invocar servicios de otras aplicaciones. Por ejemplo:

  1. Que el ISBN de un libro exista en el servicio internacional de ISBN.
  2. Que la fecha de publicación del libro sea mayor que la fecha de nacimiento del autor.

En el contexto de Spring, la lógica de la aplicación está implementada mediante clases anotadas por @Service.

La capa de lógica en nuestros proyectos

La Figura 1 presenta los elementos de la arquitectura de las aplicaciones que estamos desarrollando. La capa de lógica contiene las clases anotadas por @Service y son la fachada para el uso de los servicios que ofrece el Backend de la aplicación. En los proyectos que estamos desarrollando el cliente del Backend es un API REST (o las pruebas junit). Los objetos que maneja el Backend y que transfiere entre las capas son entidades de persistencia, es decir, clase Java anotadas con @Entity.

El Backend no conoce DTOs ni Json ni ninguna otra representación de los recursos.

Figura 1
Figura 1

El diagrama de clases de la Figura 2 presenta para dos módulos su fachada AuthorService> y EditorialService, y su relación con la capa de persistencia. El diagrama no lo muestra pero, cuando la lógica invoca métodos en la persistencia, lo que viaja son entidades. En este caso AuthorEntity y EditorialEntity.

Figura 2
Figura 2

Veamos ahora cómo la lógica se comunica con la persistencia a través de la inyección de dependencias.

Inyección de Dependencias

La mayoría de las aplicaciones en Java utilizan recursos y servicios, tales como fuentes de datos o servicios web externos. El uso de estos recursos se convierte en algo simple en Spring mediante la inyección de dependencias.

La inyección de dependencias permite que un recurso A declare una dependencia a un recurso B y delega la resolución de la misma al contenedor. El contenedor se ocupa de resolver y entregar una instancia del recurso B y se lo "inyecta" al recurso A.

Veamos dos ejemplos: i) el controlador inyectando la lógica y ii) la lógica inyectando la persistencia.

Inyección de la lógica en el controlador

En el contexto de nuestro ejemplo tenemos que el controlador CompanyController define una variable cuyo tipo es una interface de la lógica. Utilizamos la anotación @Autowired para indicarle al contenedor que en ejecución "inyecte", es decir, haga que la variable apunte a un objeto de una clase que implementa esa interfaz.

@RestController
@RequestMapping("/authors")
public class CompanyController {

    @Autowired
    private CompanyService companyService;
    ... 
}

Inyección de la persistencia en la lógica

La clase de la lógica de company define una variable para acceder a la persistencia de tipo CompanyRepository. Utilizamos la anotación @Autowired para indicarle al contenedor que en ejecución "inyecte", es decir, haga que la variable apunte a un objeto de una clase que CompanyRepository.

@Service
public class CompanyService {

    @Autowired
    private CompanyRepository repository;
  ... 
}

Validación de las reglas de negocio

La lógica de la aplicación es responsable de comunicar la capa de controladores (o recursos) con la persistencia. Esta capa no sabe de DTOs y solo manipula objetos Entity. Esta capa es responsable además de verificar reglas de negocio.

Para ilustrar verificaciones de reglas de negocio en nuestro ejemplo hemos definido las siguientes:

  1. No puede haber dos compañías con el mismo nombre
  2. No puede haber dos departamentos de la misma compañía con el mismo nombre
  3. Un empleado no puede tener un salario superior a 50 millones.

Vamos a explicar la primera regla de negocio. Esta se debe validar en dos ocasiones: cuando se crea una nueva compañía y cuando se modifica una compañía que ya existe. El siguiente fragmento de código presenta el método en la lógica para crear una compañía.

La lógica recibe el objeto ComanyEntity que se quiere crear. Este es un objeto enviado por el API. Lo primero que debe hacer es llamar a la persistencia para que consulte en la base de datos si ya existe una compañía con el nombre de la que se quiere crear (método findByName). Si ya existe, significa que la regla de negocio no se está validando y en ese caso se dispara una excepción. Si no existe se procede con la creación de la nueva compañía a través de la persistencia.

@Service
public class CompanyService {

  @Autowired
  private CompanyRepository repository;
  
  ...
  @Transactional
  public CompanyEntity createCompany(CompanyEntity entity) throws IllegalOperationException {
    List<CompanyEntity> alreadyExist = repository.findByName(entity.getName());
    if(!alreadyExist.isEmpty()) {
        throw new IllegalOperationException("Ya existe una compañía con ese nombre");
    } else {
        return repository.save(entity);
    }
  } 
...
}

Para la validación de la segunda regla de negocio: "No puede haber dos departamentos de la misma compañía con el mismo nombre" se debe hacer al crear un departamento en la lógica del departamento.

En este ejemplo, se decidió en el API REST que para crear un departamento se debe hacer a través de la compañía al que pertenece:

POST /companies/123/department

supongamos que el JSON es:

{ "name" : "Relaciones Públicas"}

En la lógica DepartementLogic tenemos el método de creación de un departamento dada una compañía (su id) donde se debe verificar la regla de negocio. El siguiente fragmento de código presenta el método en la lógica para crear un departamento. Note que, debido a nuestro diseño del API, la signatura de método **createDepartment **recibe como parámetro el identificador de la compañía y el entity que viene del API como una conversión del DTO que traía el JSON (Línea 5). En la línea 6 se llama a un método de la persistencia que busca si para la compañía identificada con companyId ya existe un departamento con el nombre dado. Si ya existe, en la línea 8 se dispara la excepción y si no, en la línea 13 se invoca la creación del departamento.

@Stateless
public class DepartmentLogic implements IDepartmentLogic {
...
@Override
public DepartmentEntity createDepartment(Long companyid, DepartmentEntity entity) throws BusinessLogicException {
DepartmentEntity alreadyExist = getDepartmentByName(companyid, entity.getName());
if (alreadyExist != null) {
throw new BusinessLogicException("Ya existe un departamento con ese nombre en la compañía ");
} else {
CompanyEntity company = companyLogic.getCompany(companyid);
entity.setCompany(company);

entity = persistence.create(entity);
}
return entity;
}
...
}

Este libro fue creado para el curso ISIS2603 Desarrollo de Sw en Equipos en la Universidad de los Andes. © Desarrollado por Rubby Casallas con la colaboración de César Forero, Kelly Garcés y Jaime Chavarriaga. Universidad de los Andes, Bogotá, Colombia. 2019

Clone this wiki locally