Pular para o conteúdo principal

Value Object

Um Value Object e um objeto de dominio sem identidade propria. Dois Value Objects sao considerados iguais quando seus atributos sao estruturalmente identicos.

Assinatura

abstract class ValueObject<TProps, TPropsJson> extends ClassDomainModels<
TProps,
TPropsJson
> {
equals(input: ClassDomainModels<TProps, TPropsJson>): boolean;
}

Comparacao estrutural

O metodo equals() compara Value Objects serializando ambos para JSON e comparando as strings resultantes:

equals(input: ClassDomainModels<TProps, TPropsJson>): boolean {
if (!input || input.constructor !== this.constructor) return false;
return JSON.stringify(this.toJSON()) === JSON.stringify(input.toJSON());
}

Regras:

  • Retorna false se input for nulo/undefined
  • Retorna false se os construtores forem diferentes
  • Compara a representacao JSON completa dos dois objetos
  • Todos os TypeFields sao desembrulhados para primitivos antes da comparacao

Quando usar Value Object vs Entity

CriterioValue ObjectEntity
IdentidadeNao possui — definido pelos atributosPossui — definido pelo ID
IgualdadePor estrutura (todos os campos)Por identidade (ID)
Ciclo de vidaSubstituivel — trocar por outro com mesmos valoresRastreavel — persiste com mesmo ID
ExemplosEndereco, Dinheiro, Periodo, CoordenadaUsuario, Pedido, Conta, Produto

Regra pratica: se dois objetos com os mesmos valores sao intercambiaveis no dominio, use Value Object. Se precisam ser rastreados individualmente ao longo do tempo, use Entity.

Exemplo

import { ValueObject, FString, FInt } from "tyforge";

// 1. Defina os tipos
interface IEnderecoProps {
rua: FString;
numero: FInt;
cidade: FString;
}

interface IEnderecoJson {
rua: string;
numero: number;
cidade: string;
}

// 2. Implemente o Value Object
class Endereco extends ValueObject<IEnderecoProps, IEnderecoJson> {
protected readonly _classInfo = {
name: "Endereco",
version: "1.0.0",
description: "Endereco completo",
};

rua: FString;
numero: FInt;
cidade: FString;

private constructor(props: IEnderecoProps) {
super();
this.rua = props.rua;
this.numero = props.numero;
this.cidade = props.cidade;
}

static create(props: IEnderecoProps): Endereco {
return new Endereco(props);
}
}

// 3. Comparacao estrutural
const end1 = Endereco.create({
rua: FString.createOrThrow("Rua das Flores"),
numero: FInt.createOrThrow(100),
cidade: FString.createOrThrow("Curitiba"),
});

const end2 = Endereco.create({
rua: FString.createOrThrow("Rua das Flores"),
numero: FInt.createOrThrow(100),
cidade: FString.createOrThrow("Curitiba"),
});

end1.equals(end2); // true — mesmos valores

// Serializar
const json = end1.toJSON();
// { rua: "Rua das Flores", numero: 100, cidade: "Curitiba" }

Heranca

ValueObject e a classe base para Dto, que adiciona campos especificos para transporte HTTP. Veja Dto para mais detalhes.