Patrones de diseño en DDD: Objetos-Valor

jueves, 20 de febrero de 2014

Este blog no esta mantenido, suscribite a la newsletter del nuevo

En anteriores post he hablado de las Entidades

Patrones de diseño en DDD: Entidades
Patrones de diseño en DDD: Validación en las entidades

Ahora toca el turno a otro patrón de diseño habitual en DDD como son los Objetos-Valor.


El ejemplo mas simple de objeto-valor son los valores primitivos de .Net como los números, si tu tienes una variable de tipo entero con valor 5, este valor no se puede editar, lo que se hace es sustituirlo por otro número. Además dos objetos con el valor 5 se asume que tienen el mismo número.

En objetos-valor mas complejos donde hay varias propiedades el comportamiento va a ser el mismo, es decir, no se va a poder editar se va a poder sustituir.

Las características de este tipo de objeto de modelo de dominio son:

  • Al contrario que las entidades, tienen una identidad basada en sus atributos
  • Normalmente una dirección se representa como un objeto-valor, aunque esto depende mucho del dominio con el que estés trabajando, y  si dos objetos usuario tienen una dirección con los mismos valores se asume que es la misma dirección.
  • Es inmutable, no puede cambiar. No se pueden cambiar los valores de un objeto dirección, se sustituye un objeto dirección por otro.
  • como ejemplos de objetos-valor pueden ser dirección, precio (cantidad, moneda)
  • Objetos-valor se pueden comparar mediante equals
Vamos a ver ejemplos de como se representan normalmente Objetos-valor en el dominio y como se persisten en una base de datos como SQL Server.

Lo normal es que las propiedades de un Objeto-Valor se representen en base datos como columnas de la tabla de su entidad root.

En un ejemplo de usuario y dirección lo tenemos que en base de datos se podría representar así:

CREATE TABLE [dbo].[User](
 [UserId] [int] NOT NULL,
 [UserName] [varchar](50) NULL,
 [City] [varchar](50) NULL,
 [Country] [varchar](50) NULL,
 [PostalCode] [tinyint] NULL,
 [Region] [varchar](50) NULL,
 [Street1] [varchar](50) NULL,
 [Street2] [varchar](50) NULL,
 CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED 
(
 [UserId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

Y sin embargo en el modelo de dominio al ser la dirección un objeto-valor, es más útil crear un objeto-valor para la dirección y que herede de una clase objeto-valor base con funcionalidad común como la redefinición de equals comparando todos las propiedades para decicir si dos objetos son el mismo.


Ahora veamos otro ejemplo, otro caso de objeto-valor suele ser money. En base de datos son dos campos como PriceAmount y PriceCurrency pero en el modelo del dominio lo que tenemos es una propiedad price en el producto de tipo money, money seria el objeto-valor, con toda una funcionalidad de conversiones de moneda, donde podría redefinir operadores de mayor, menor , igual etc..
CREATE TABLE [dbo].[Product](  [ProductId] [int] IDENTITY(1,1) NOT NULL,  [Price] [decimal](18, 2) NULL,  [CurrencyCode] [varchar](3) NULL,  CONSTRAINT [PK_Product] PRIMARY KEY CLUSTERED (  [ProductId] ASC)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]) ON [PRIMARY]GO



En los objetos-valor no se puede editar sus valores, si os fijáis es la entidad root es la que contiene un método para sustituir uno por otro, como en el ejemplo de producto que hay un método ChangePrice.

¿Cómo podemos mapear un objeto de modelo de dominio con columnas de la tabla de su entidad root en base de datos?

Si usamos un ORM como Entity Framework, para poder mapear Objetos-Valor a columnas de la tabla de su entidad podemos usar Complex types de entity framework, escribí un post explicando como hacer esto con Code First.

Como mapear los Objetos-Valor de Dominio (DDD) en Sql Server con Entity Framework

Libros Relacionados

Domain-Driven Design: Tackling Complexity in the Heart of Software

Implementing Domain-Driven Design

1 comentario:

  1. Para que quiero guardar datos sin ninguna referencia? Es decir un tipo complejo me sirve igual que un string de propiedaes osea que es como otra variable pero @compleja, es decir puede ser destruida y no nos interesa tener noción de su modificación. A lo que me refiero es si esto dependerá del dominio porque me importa saber bastante si para el dominio es importante guardar y llevar un log de las direcciones debería hacer una entidad con esto cierto? Sino me importa la volatilidad de estos datos entonces usaria un objeto valor.

    ResponderEliminar