Giter Site home page Giter Site logo

jee-dci's Introduction

El patrón de diseño DCI

DCI ha devenido en uno de los patrones que siempre tengo a mano para usar cuando programo. Complementario con MVC y no tan afamado como éste, he podido encontrar en su aplicación una forma estándar y simple de organizar los artefactos en la implementación de lógicas de negocio complejas.

Datos, Contexto e Interacción(DCI) es un patrón de diseño utilizado en el desarrollo de sistemas complejos para aportar mecanismos simples, bien definidos, robustos y uniformes en la organización, implementación e invocación de la lógica de negocio.

Entre sus objetivos están:

  • Simplificar la implementación de la lógica de negocio y sus dependencias de ejecución mediante la creación de contextos.

  • Estandarizar la implementación de la lógica de negocio mediante el uso de convenciones simples.

  • Facilitar el cambio de la lógica de negocio del sistema de manera ágil mediante el bajo acoplamiento del código.

  • Mejorar la comprensión del flujo del sistema mediante el otorgamiento de un status de primera clase a la lógica de negocio.

DCI conceptualiza la implementación de la lógica de negocio en tres partes:

  • Datos: son todos los datos necesarios para la implementación de la lógica de negocio.

  • Contexto: es la agrupación de los datos y asignación de roles a los mismos. La asignación de roles se explica en que un dato puede ser interpretado en contextos diferentes de diferentes formas. Por ejemplo: suponiendo un sistema de gestión de salud, los datos de una persona pueden estar en rol de Paciente en un contexto de aplicación de un tratamiento médico, o en rol de Acompañante en el contexto de ciudados de otro paciente. El contexto define un dominio autocontenido y sensible a validación para la ejecución de la lógica de negocio.

  • Interacción: es la implementación de la lógica de negocio. Para ello hace uso del contexto válido pues en él están todos los datos y roles suficientes.

    Datos                      Contexto                 Interacción

  +--------+   Usado(s) en   +----------+  Usado en   +-------------+
  | dato 1 +---------------->| rol 1    +------------>|             |
  +--------+ +-------------->| rol 2    |             |  Lógica de  |
             | +------------>|          |             |  Negocio    |
  +--------+ | |             | rol N    |             |             |
  | dato 2 +-+ |             +----------+             +-------------+
  +--------+   |
               |
  +--------+   |
  | dato N +---+
  +--------+

DCI se puede ver como una aplicación del Principio de Responsabilidad Única a la implementación de la lógica de negocio de un sistema.

DCI fue inventado por Trygve Reenskaug y James O. Coplien, científicos de la computación. Trygve Reenkaug también es el inventor del patrón de diseño MVC.

MVC y DCI son patrones complementarios, pues se centran en partes diferentes del funcionamiento de los sistemas. El dominio de aplicación de MVC comprende la interacción de los usuarios con la interfaz de la aplicación/sistema: información a mostrar, procesamiento de eventos de la interfaz de usuario, recepción y respuesta a peticiones, etc.

El dominio de aplicación de DCI es la ejecución de la lógica de negocio, por lo cual MVC se puede apoyar en DCI para dar respuesta a la petición de un usuario.

Es común ver la implementación de lógica de negocio en los Controladores del patrón MVC, lo cual es factible para operaciones triviales en sistemas no complejos con lógica de aplicación que raramente cambia. Pero cuando los sistemas comienzan a crecer, no aplicar DCI conlleva a una creciente complejidad de los controladores, mayor acoplamiento de código, mayor dificultad en la detección/corrección de errores y pérdida de agilidad para responder a los cambios en la lógica de negocio.

Esta implementación consta de tres artefactos:

  • Interfaz Contexto: define el comportamiento de un contexto básicamente como una entidad sensibles a ser validada. Las clases que implementen esta interfaz deben adicionar los diferentes roles que serán utilizados en sus contextos específicos y dar una definición de cuándo es válido el contexto, a través de la implementación del método:

public boolean esValido();
  • Excepción ContextoNoValido: Es lanzada en la ejecución de una interacción si al invocar el método esValido() del contexto relacionado con la interacción se devuelve false.

  • Clase abstracta InteraccionBasica: define cómo se ejecuta cualquier lógica de negocio de una interacción a través del método ejecutar() que en ningún caso debe ser redefinido en clases hijas. El método no ha sido declarado como final pues no permitiría usar CDI como vía de implementación de las interacciones.

...
public abstract class InteraccionBasica implements Serializable {

	private static final long serialVersionUID = 1L;

	public Object ejecutar() throws ContextoNoValido, Exception {

		if (!getContexto().esValido()) throw new ContextoNoValido(getContexto().toString());

		Object o = ejecucionDeLaLogicaDeNegocio();

		return o;
	}

	protected abstract Object ejecucionDeLaLogicaDeNegocio();

	public abstract Contexto getContexto();
}

Adicionalmente cualquier clase Interaccion que extienda de InteraccionBasica debe proveer implementaciones concretas para los métodos ejecucionDeLaLogicaDeNegocio y getContexto. En el método ejecucionDeLaLogicaDeNegocio es donde deben centrarse los esfuerzos del desarrollador por brindar una implementación adecuada de la misma.

A continuación se considera el caso de uso de búsqueda de una persona dado su id.

...
public class ContextoBusquedaDePersonaPorId implements Contexto, Serializable { // (1)

  private static final long serialVersionUID = 1L;

  private EntityManager em; // (2)

  private BigDecimal id; // (2)

  @Override public boolean esValido() { return getEm() != null && getId() != null; } // (3)
  // getters y setters no incluidos
}
  1. El contexto ContextoBusquedaDePersonaPorId implementa las interfaces Contexto y Serializable.

  2. Se definen los datos y roles que necesita el contexto, ej: em es un EntityManager que referencia a una fuente de Datos.

  3. Se brinda una implementación del método esValido acorde al contexto. En este caso el contexto es válido cuando los campos id y em no son null.

La interacción InteraccionBusquedaDePersonaPorId:

...
@Model // (1)
public class InteraccionBusquedaDePersonaPorId extends InteraccionBasica { // (2)

  private static final long serialVersionUID = 4591028478174556531L;

  private final ContextoBusquedaDePersonaPorId contexto = new ContextoBusquedaDePersonaPorId(); // (3)

  @Override
  public Contexto getContexto() { return contexto; } // (4)

  @Override
  protected Object ejecucionDeLaLogicaDeNegocio() {  // (5)

    // Implementación de la lógica de negocio

    return _resultado;
  }
}
  1. La anotación @Model indica que estamos en presencia de un CDI bean el cual podrá ser inyectado como dependencia utilizando el nombre interaccionBusquedaDePersonaPorId. La dependencia tiene un ámbito de Request.

  2. La interacción extiende la clase InteraccionBasica.

  3. Se declara e instancia el contexto asociado a la interacción. Con la instanciación se asegura que no es nulo, evitando chequeos innecesarios.

  4. Se define el método getContexto.

  5. Se define el método ejecucionDeLaLogicaDeNegocio donde se implementa la lógica de negocio en concreto.

El uso del contexto y la interacción se hace a través de un EJB que brinda un contexto de ejecución transaccional a la lógica de negocio así como un punto de entrada estandar para su uso.

La interfaz del EJB define el comportamiento del mismo. Como pauta se debe definir un método ejecutar con parámetros en dependencia del caso de uso. Estos parámetros son los datos utilizados en el contexto.

...
public interface ServIntBusquedaDePersonaPorId {

	public Object ejecutar(BigDecimal id) throws ContextoNoValido, OptimisticLockException, Exception; // (1)
}
  1. Declaración del método con las excepciones que puede lanzar.

Implementación de la interfaz:

...
@Stateless // (1)
public class ServImpBusquedaDePersonaPorId implements ServIntBusquedaDePersonaPorId, Serializable{

  private static final long serialVersionUID = 1L;

  @PersistenceContext
  transient private EntityManager em; // (2)

  @Inject
  transient private InteraccionBusquedaDePersonaPorId interaccion; // (3)

  @Override
  public Object ejecutar(BigDecimal id) throws ContextoNoValido, OptimisticLockException, Exception {

    // (4)
    ContextoBusquedaDePersonaPorId ctx = (ContextoBusquedaDePersonaPorId)interaccion.getContexto();

    ctx.setEm(em);
    ctx.setId(id);

    return interaccion.ejecutar();
  }
}
  1. Decora la clase como definición de objetos EJBs sin estado.

  2. Se inyecta el recurso EntityManager que va a ser utilizado en el contexto.

  3. Se inyecta el CDI bean de la interacción.

  4. Una implementación estándar: se setean los datos relevantes al contexto y se devuelve el resultado de la ejecución de la interacción.

Una vez implementados los artefactos, se puede utilizar el servicio en el controlador CDI bean inyectando el EJB e invocando el método ejecutar:

...
@Named
public class PersonaDatos implements Serializable {
  ...
  @EJB
  transient private ServIntBusquedaDePersonaPorId busquedaDePersonaPorId; // (1)

  public void buscar(BigDecimal id) {

    if (id != null) {
      try {
        Persona _p = (Persona) busquedaDePersonaPorId.ejecutar(id); // (2)
      } catch (Exception _e) {_e.printStackTrace();}
    }
  }
  ...
}
  1. Inyección del EJB.

  2. Invocación del método ejecutar.

La utilización del patrón de diseño DCI me ha facilitado la programación de lógica de negocio compleja y ha hecho mi código más fácil de comprender por otras personas. Como siempre ocurre, no es una bala de plata, su aplicación en casos de lógica simple no es necesaria pues al menos hay que implementar un contexto y una interacción por cada caso de uso.

Si has tenido experiencias haciendo uso del patrón y quisieras compartirlas quedo atento :)

jee-dci's People

Contributors

kellsaro avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.