[CQS] - Principio Command Query Separation

Descripción general

Command Query Separation (CQS), o en castellano separación de comandados y consultas, es un principio de diseño que fue acuñado por Bertrand Meyer en su libro Object Oriented Software Construction en el cual nos dice lo siguiente: A method should either Change the State of an Object [the COMMAND], or Return a Result [the QUERY], but Not Both [the SEPARATION]. Traduccion: Una operación debe ser un command o una query, pero nunca ambas.

[TOC] Tabla de Contenidos


↑↑↑

Introducción:

Imágen del princípio CQS

Imágen del princípio CQS

La idea principal detrás de este principio es que debemos dividir los métodos de un objeto en dos categorías, ya que al realizar una pregunta, esta no debe cambiar la respuesta. Como resultado de aplicar este principio consistentemente ayuda a que los desarrolladores puedan entender mejor y más rápido el código.


↑↑↑

Aplicando CQS

Antes

Vemos una clase ficticia que tiene dos métodos: EliminarCuenta y AgregarCuenta. Como se ve a continuación ambos métodos cambian el estado del sistema y devuelven resultados.

Public Class ServicioFinancieroAntes

    Public Function EliminarCuenta(ByVal cuentaParaBorrar As cuenta) As IEnumerable(Of cuenta)
        repositorioCuenta.delete(cuentaParaBorrar)
        repositorioCuenta.save()

        ' buscar los registros que tengan el ID (cuentaParaBorrar.PersonaId)
        ' en el repositorio. Si se han borrado no debe quedar ninguno
        Dim listadoCuentas As IEnumerable(Of cuenta) =
                From registro As cuenta In repositorioCuenta.ToList
                Where String.Equals(cuentaParaBorrar.PersonaId, registro.PersonaId) = True
                Select registro

        Return listadoCuentas
    End Function

    Public Function AgregarCuenta(ByVal cuenta As cuenta) As ResultadoE
        If String.IsNullOrEmpty(cuenta.Numero) Then
            Return ResultadoE.NumeroInvalido
        End If

        If (cuenta.PropietarioId = 0) Then
            Return ResultadoE.PropietarioInvalido
        End If

        repositorioCuenta.Add(cuenta)
        repositorioCuenta.save()
        Return ResultadoE.Exito
    End Function
End Class

Después

Aplicando este principio ahora tenemos dos comandos: AgregarCuenta y EliminarCuenta y dos consultas: ValidarCuenta y ConsultarCuentas.

Public Class ServicioFinancieroDespues

    Public Function ValidarCuenta(ByVal cuenta As cuenta) As ResultadoE
        If String.IsNullOrEmpty(cuenta.Numero) Then
            Return ResultadoE.NumeroInvalido
        End If

        If (cuenta.PropietarioId = 0) Then
            Return ResultadoE.PropietarioInvalido
        End If
        Return ResultadoE.Exito
    End Function


    Public Sub AgregarCuenta(ByVal cuenta As cuenta)
        repositorioCuenta.Add(cuenta)
        repositorioCuenta.save()
    End Sub

    Public Sub EliminarCuenta(ByVal cuenta As cuenta)
        repositorioCuenta.delete(cuenta)
        repositorioCuenta.save()
    End Sub

    Public Function ConsultarCuentas(ByVal cuentaConsultada As cuenta) As IEnumerable(Of cuenta)
        ' buscar los registros que tengan el ID (cuentaParaBorrar.PersonaId)
        Dim listadoCuentas As IEnumerable(Of cuenta) =
                 From registro As cuenta In repositorioCuenta.ToList
                 Where String.Equals(cuentaConsultada.PersonaId, registro.PersonaId) = True
                 Select registro
        Return listadoCuentas
    End Function
End Class


↑↑↑

Cuando no aplicar CQS:

No es conveniente aplicar CQS en un escenario multihilo, porque la implementación se vuelve más difícil.

Antes

Public Class EjemploBloqueosAntes
    Dim contador As Integer = 0
    Dim recurso As Object = New Object
    Dim bloqueado As String = "bloquéame"

    Public Function Incrementar() As Integer
        SyncLock bloqueado
            contador = (contador + 1)
            Dim copia As Integer = contador
            Return copia
        End SyncLock
    End Function
End Class

Después

Public Class EjemploBloqueosDespues
    Dim contador As Integer = 0
    Dim recurso As Object = New Object
    Dim bloqueado As String = "bloquéame"

    Public Sub Incrementar()
        SyncLock bloqueado
            contador = (contador + 1)
        End SyncLock
    End Sub

    Public Function Obtener() As Integer
        Return contador
    End Function
End Class


↑↑↑

Conclusiones:

El principio Comman Query Separation (CQS), acuñado por Bertrand Meyer en su libro Object Oriented Software Construction, señala que un método no puede realizar dos tareas a la vez, cambiar el estado del sistema (Command) y devolver un resultado (Query), para esto se debe dividir los métodos de un objeto en dos categorías. Pero debemos tener en cuenta que hay ciertos casos en donde es mejor no aplicar este principio para no volver más complejo el diseño.


↑↑↑

A.2.Enlaces

[Para saber mas]
[Grupo de documentos]
[Documento Index]
[Documento Start]
[Imprimir el Documento]
© 1997 - - La Güeb de Joaquín
Joaquín Medina Serrano
Ésta página es española

Codificación
Fecha de creación
Última actualización
[HTML5 Desarrollado usando CSS3]