Mudanças entre as edições de "MeasureRuler"

De Wiki do Leitão
Ir para: navegação, pesquisa
(Criou página com 'O MeasureRuler é, pela própria tradução, uma régua de medidas. Essa régua de medidas tem a intenção de oferecer aos sistemas a facilidade para converter unidades de medidas da mesma dimensão, ou até mesmo entre dimensões diferentes quando estabelecida a regra de conversão. Definições: * '''Dimensão''' - tipo de medida utiliza, como "Comprimento", "Área", "Volume", "Massa (Peso)", etc. Embora estas hoje sejam as dimensões que o BIS suporta, nada impede d...')
 
 
(5 revisões intermediárias pelo mesmo usuário não estão sendo mostradas)
Linha 64: Linha 64:
Para evitar esse problemas as unidades de medidas devem '''sempre ter nomes diferentes mesmo que em dimensões distintas'''. Embora não conheça nenhuma unidade de medida que tenha o mesmo o nome e represente coisas diferentes, é bom que o DEV tenha ciência dessa situação.
Para evitar esse problemas as unidades de medidas devem '''sempre ter nomes diferentes mesmo que em dimensões distintas'''. Embora não conheça nenhuma unidade de medida que tenha o mesmo o nome e represente coisas diferentes, é bom que o DEV tenha ciência dessa situação.
}}
}}
= Utilização da Régua =
Para realizar a conversão das unidades de medidas devemos focar nos métodos '''.convertTo(...)''' da classe '''MeasureRuler'''. Há métodos simples utilizados para conversão dentro da mesma dimensão (sem utilização de equivalências) até métodos completos com a entrada de equivalências e definição da precisão de casas decimais.
== Exemplos de Utilização ==
Veja alguns exemplos de utilização da MeasureRuler:
{{java|Conversão de Unidade de Medida dentro da Mesma Dimensão|<syntaxhighlight lang="java">
  // Converte 1000ml em Litros, retornará um BigDecimal com o valor de 1.000
  MeasureRuler.convertTo(new BigDecimal("1000"), VolumeUnit.MILLILITER, VolumeUnit.LITER);
  // Converte 1000ml em Litros, mas dessa vez retornará com a precisão de 6 casas decimais.
  MeasureRuler.convertTo(new BigDecimal("1000"), VolumeUnit.MILLILITER, VolumeUnit.LITER, 6);
  //  Converte 1000g em Kilogramas, com uma precisão de 6 casas decimais, retornará o valor 1.000000
  MeasureRuler.convertTo(new BigDecimal("1000"), WeightUnit.GRAM, WeightUnit.KILOGRAM, 6);
</syntaxhighlight>}}
Para converter entre diferentes dimensões (grandezas de medidas diferentes), vamos primeiro estabelecer uma regra de equivalência entre as grandezas, podendo ser feita com qualquer unidade de medida da grandeza.
Vejamos um exemplo, imagine um sistema de marcenaria que precise cadastrar uma chapa de madeira utilizada para móveis. No estoque e durante o processo de compra, referenciamos o item por unidades, pois fica mais fácil de fazer o pedido e comparar preços. Mas no momento de calcular o frete, precisamos saber qual o peso de cada chapa, ou qual o peso final do móvel produzido, de acordo com a "quantidade de chapa" (medida em metros quadrados (área)) que foi recortado e utilizado. Para ter todas essas informações precisamos estabelecer a relação entre as grandezas '''Unidades''', '''Massa (Peso)''' e '''Área'''.
Imagine que após verificar o produto, descobrimos que a chama tem medida de 2m x 1,8m (=3,6m²), e que ela pesa 76Kg. Assim, montamos nossos dados de equivalência:
{{java|Criando Regras de Equivalência|<syntaxhighlight lang="java">
  // Regras de Equivalência
  MeasureRulerEquivalence eqVO = new MeasureRulerEquivalence();
  eqVO.getMeasureUnitHash().put(UnitUnit.UNIT, new BigDecimal("1")); // Definimos que cada 1 Unidade...
  eqVO.getMeasureUnitHash().put(WeightUnit.KILOGRAM, new BigDecimal("76")); // equivale a 76Kg...
  eqVO.getMeasureUnitHash().put(AreaUnit.SQUAREMETER, new BigDecimal("3.6")); // e a 3,6m²
</syntaxhighlight>}}
Com as regras de equivalência o '''MeasureRuler'' conseguirá converter unidades conforme a necessidade. Vamos imaginar que o marceneiro precisa saber quantas chapas vamos precisar para cobrir uma área de 40m². Assim convertemos na régua:
{{java|Convertendo Entre as Dimensões|<syntaxhighlight lang="java">
  // Chamamos a MeasureRuler, mas agora passando as regras de conversão
  BigDecimal v = MeasureRuler.convertTo(eqVO, new BigDecimal("40"), AreaUnit.SQUAREMETER, UnitUnit.UNIT, 6);
  // o Valor de v será equivalente a 11.111111, com 6 casas decimais de precisão, conforme solicitado
</syntaxhighlight>}}


= Unidades de Medidas Personalizadas =
= Unidades de Medidas Personalizadas =


O MeasureRuler permite que o usuário crie suas próprias unidades de medidas bastando apenas definir um nome e um símbolo. Em uma classe que estenda a interface '''MeasureUnit'''. Para que a unidade de medida se torne funcional será ainda necessário estabelecer uma régua de equivalências, explicado no tópico de utilização.
O MeasureRuler permite que o usuário crie suas próprias unidades de medidas bastando apenas definir um nome e um símbolo em uma classe que estenda a interface '''MeasureUnit'''. Depois, para que a unidade de medida se torne funcional basta adiciona-la a régua de equivalências como no exemplo anterior.
 
Imagine que o marceneiro do exemplo anterior, é de uma cidade esquisita e que lá existe uma unidade de medida "XYZ", utilizada localmente, cujo símbolo é "Xz" e que representa 7 Unidade. Para adicionar essa nova unidade na nossa equivalência bastaria criar um objeto implementando a interface '''MeasureUnit''', como dito anteriormente. Veja o exemplo:
 


{{java|Unidade de Medida Personalizada|<syntaxhighlight lang="java">


{{nota|Persistência de Unidades de Medidas Personalizadas|Vale ressaltar que as unidades de medidas personalizadas não podem ser persistidas com o MeasureUnitDAOConverter. Esses objetos devem ser persistidos em atributos separados como um objeto do sistema, ou o desenvolvedor deve implementar seu próprio converter para o determinado atributo.}}
  // Mesma régua de equivalências do exemplo anterior
  MeasureRulerEquivalence eqVO = new MeasureRulerEquivalence();
  eqVO.getMeasureUnitHash().put(UnitUnit.UNIT, new BigDecimal("1"));
  eqVO.getMeasureUnitHash().put(WeightUnit.KILOGRAM, new BigDecimal("76"));
  eqVO.getMeasureUnitHash().put(AreaUnit.SQUAREMETER, new BigDecimal("3.6"));


= Estabelecendo Paridade de Conversão - MeasureRulerEquivalenceIntercade =
  // Vamos utilizar a classe CustomMeasureUnitGeneric que implementa a interface necessária, para criar nossa unidade de medida personalizada
  CustomMeasureUnitGeneric xyz = new CustomMeasureUnitGeneric("XYZ", "Xz");


Embora o MeasureRuler já seja capaz de converter unidades de medidas dentro da mesma dimensão, é possível estabelecer equivalências entre as unidades de medidas. Como, por exemplo, estabelecer que 1 unidade tem 50g, e depois disso pedir que a régua converta 1 Dúzia em Kilos.
  // Agora incluímos nossa unidade de medida com o peso de 7 (pois é 7Xz para 1 Unidade)
  eqVO.getMeasureUnitHash().put(xyz, new BigDecimal("7"));


Essas paridades são definidas apenas implementando a interface '''MeasureRulerEquivalenceInterface'''. Nela há apenas um método que deve retornar uma '''Hash<MeasureUnit, BigDecimal>'''. A chave da hash é qualquer unidade de medida, e seu valor é um BigDecimal que estabelece o peso da unidade de medida. Exemplos:
</syntaxhighlight>}}
* '''1 Unidade = 50g = 30ml''' - Devemos ter os seguintes objetos na Hash:
 
** hash.put(UnitUnit.UNIT, BigDecimal.ONE);
 
** hash.put(WeightUnit.GRAM, new BigDecimal("50");
Note que o peso foi 7 porque nossa régua está criada com peso de 1 em unidades. Se nossa equivalência fosse 7Xz para 2 Unidades, teríamos que trocar o peso de 7 para 3,5Xz. Quando montamos a régua de equivalência temos que colocar os pesos que sejam compatíveis. No nosso exemplo, o código seria lido como se fosse a seguinte igualdade:
** hash.put(VolumeUnit.MILILITER, new BigDecimal("30");
 
<center><pre>1 Unidade = 76Kg = 3,6m² = 7Xz</pre></center>
 
 
== Equivalências Despareadas ==
 
Este é um recurso criado apenas para simplificar e permitir que o MeasureRuler faça os cálculos pra você no momento de adicionar as equivalências desconectadas.
 
Por exemplo, imagine que você tenha as seguinte igualdades de equivalência:
 
<center><pre>1 Unidade = 36g
2m² = 12,4Kg</pre></center>
 
Nessa situação teríamos que calcular as igualdade de maneira que se tornassem todas proporcionais, unificando a unidade de medida de Massa em "g" ou em "Kg" e recalculando a razão da outra unidade de medida. Até termos algo como:
 
<center><pre>1 Unidade = 36g => 0,001 Unidade = 0,036Kg => 0,3444444 Unidades = 12,4Kg
2m² = 12,4Kg</pre></center>
 
para que então possamos estabelecer a equivalência entre todos:
 
<center><pre>0,3444444 Unidades = 12,4Kg = 2m²</pre></center>
 
 
 
Para evitar esse trabalho todo externo a interface '''MeasureRulerEquivalenceInterface''' tem um método "default" chamado '''addComparativeEquivalence''' que permite adicionar essas referências descasadas diretamente. Vejamos o código no nosso exemplo acima:
 
 
 
{{java|Unidade de Medida Descasada|<syntaxhighlight lang="java">
 
  // Criamos a régua e incluímos nossa primeira equivalência ligando duas dimensões
  MeasureRulerEquivalence eqVO = new MeasureRulerEquivalence();
  eqVO.getMeasureUnitHash().put(UnitUnit.UNIT, new BigDecimal("1"));
  eqVO.getMeasureUnitHash().put(WeightUnit.GRAM, new BigDecimal("36"));
 
  // Agora já temos Unidades e Massa na régua de equivalência, podemos adicionar outra dimensão utilizando uma dessas referência
  eqVO.addComparativeEquivalence(new BigDecimal("2"), AreaUnit.SQUAREMETER, new BigDecimal("12.4"), WeightUnit.KILOGRAM);
 
</syntaxhighlight>}}
 
 
Internamente o método fará a conversão e estabelecerá os pesos corretos para conversão.
 
 
== Persistindo as Unidades de Medidas Personalizadas ==
 
Cada sistema tem autonomia para tratar a persistência como preferir, mas a metodologia utilizada pelo RFW, e que é praticada pelo '''MeasureUnitDAOCOnverter''' quando utilizado o [[RFWDAO]] é a seguinte:
 
Primeiro vamos relembrar que a MeasureUnit padrão é uma enumeration, e que o RFW mantém as enumeration com o limite máximo de 50 caracteres. Inclusive sugerindo que o campo no banco seja um '''varchar(50)'''.
 
Segundo, a unidade de medida personalizada é composta apenas de um nome e um símbolo.
 
Com essas diretrizes, a solução implementada foi, sempre que a '''MeasureUnit''' recebida para persistência for uma '''CustomMeasureUnit''', será montada uma String no formato:
<pre>"#" + value.getSymbol() + "|" + value.name()</pre>
 
Utilizamos o primeiro carácter "#" para identificar que se trata de uma serialização de '''CustomMeasureUnit''', e um "|" para separar o Símbolo do nome. Ao reler o conteúdo no banco de dados, detectamos o primeiro carácter, se encontramos o "#" montamos uma '''CustomMeasureUnit''' com o objeto '''CustomMeasureUnitGeneric''' fazendo o parser da serialização anterior.
 
 
{{nota|Objeto da Desserialização|Note que se a aplicação utilizou seu próprio objeto para implementar a interface '''CustomMeasureUnit''' o '''MeasureUnitDAOConverter''' não é capaz de retornar um objeto personalizado.
 
Como alternativa você pode implementar seu próprio converter e retornar seu objeto necessário. Ou, ainda, converter o objeto retornado quando e se for necessário. Se apenas forem necessários os métodos da interface, ele pode ser mantido.}}
 
 
 
{{nota|Limite dos Tamanhos|Seguindo essa metodologia de serializar o objeto personalizado no campo de 50 caracteres destinado a enumeration, temos que lembrar que o limite de Nome da Unidade de Medida + Simbolo será de 48, pois temos mais 2 caracteres de sinalização.
 
Esse tamanho precisa ser validado em alguma parte do sistema caso sejam estabelecidos esses parâmetros. O MeasureRuler não inclui essa validação no seu código pois ela pode ser diferente para cada sistema.}}
 
= Validação da Régua de Equivalência =
 
É importante tomar cuidado com as informações fornecidas dentro da régua de equivalências para que não sejam incoerentes.




Linha 93: Linha 227:




Com esses três objetos estabelecemos a referência entre as dimensões Unidades, Massa e Volume. Podendo converter de Toneladas para Centimetros Cúbicos, por exemplo. Para estabelecer, uma referência com uma unidade de medida personalizada basta colocar na Hash a instância da unidade de media personalizada na Hash e estabelecer o seu peso em comparação as demais unidades presentes na Hash.
= Utilização da Régua =
Para realizar a conversão das unidades de medidas, utilizando ou não a régua de equivalências e/ou unidades de medidas pesonalizadas, devemos focar nos métodos '''.convertTo(...)''' da classe '''MeasureRuler'''. Há métodos simples utilizados para conversão dentro da mesma dimensão (sem utilização de equivalências) até métodos completos com a entrada de equivalências e definição da precisão de casas decimais.
= Validação da MeasureRulerEquivalenceInterface =


A classe '''MeasureRuller''' contém um método de validação para garantir que as informações da Hash de equivalências não estão redundantes ou incoerentes.
A classe '''MeasureRuller''' contém um método de validação '''validateMeasureRulerEquivalence()''' para garantir que as informações da Hash de equivalências não estão redundantes ou incoerentes.

Edição atual tal como às 01h14min de 27 de julho de 2023

O MeasureRuler é, pela própria tradução, uma régua de medidas. Essa régua de medidas tem a intenção de oferecer aos sistemas a facilidade para converter unidades de medidas da mesma dimensão, ou até mesmo entre dimensões diferentes quando estabelecida a regra de conversão.

Definições:

  • Dimensão - tipo de medida utiliza, como "Comprimento", "Área", "Volume", "Massa (Peso)", etc. Embora estas hoje sejam as dimensões que o BIS suporta, nada impede de se criar dimensões menos usuais como "Energia", "Luminosidade", "Torque", etc..
  • Unidade de Medida - Unidade de medida utilizada para medir a Dimensão desejada. Por exemplo, comprimento pode ser medido em "Metros", "Centimetros", "Pés", "Polegadas", etc. "Massa" pode ser medida em "Arrobas", "Kilos", "Pounds", etc.

A classe MeasureRuler apresenta diversos métodos para conversão de forma. Para mais informações sobre eles consulte o JavaDoc da classe.


MeasureUnit

O MeasureRuler suporta várias dimensões de medidas. Cada dimensão pode conter várias unidades de medidas. A dimensão é definida pela enumeration MeasureDimension. Já as unidades de cada unidade de medida são definidas pela sua própria enumeration que estendem a interface MeasureUnit. Por exemplo:

  • Volume - VolumeUnit
  • Comprimento - LengthUnit
  • Área - AreaUnit
  • Massa (peso) - WeightUnit
  • Unidades - UnitUnit


Interface MeasureUnit

Cada dimensão tem suas unidades de medidas em enumerations próprias. Assim, quando precisamos representar qualquer uma das unidades de medida utilizamos essa interface. Um exemplo: ao cadastrar um produto no sistema, a "unidade básica de estoque" dele pode ser tanto Unidades, quando Metros, Kilos, Metros Quadrados, etc.. Assim, a melhor maneira de definir este atributo no VO é através desta interface.

A interface MeasureUnit apresenta métodos como getDimension(), que retorna a enumeration de MeasureDimension para indicar que Dimensão de Medida esta Unidade pertence.


Persistência da Interface MeasureUnit

MeasureUnitDAOConverter (RFWDAO)

Por tratar-se de uma enumeration, o padrão do FrameWork é que no banco seja um campo do tipo varchar(50) (O limite recomendado de enums no RFW é de 50 chars). Mas, uma vez que a MeasureUnit é uma interface, o RFWDAO não sabe como proceder para persisti-la e reconstruir o VO com os dados do banco. Para isso temos de utilizar uma RFWDAOConverter. E para simplificar, o MeasureRuler já oferece uma implementação pronta para isso a MeasureUnitDAOConverter.


Note 64.png
Classe Disponível no RFW.DAO
Apesar do Measure ser disponibilizado no RFW.Kernel, as classes de persistência e conversão estão disponibilizadas apenas no módulo RFW.DAO, afinal essas classes só fazem sentido em conjunto com o RFW.


Para definir um atributo no VO que seja do tipo MeasureUnit devemos ter algo como:

Java 256.png Exemplos de Declaração
@BISDAOConverter(converterClass = MeasureUnitDAOConverter.class)
@BISMetaGenericField(caption = "Unidade de Medida", required = true)
private MeasureUnit measureUnit = null;


Sempre que o RFWDAO ler a String no banco de dados que representa a unidade de medida, o Converter conseguirá descobrir de qual enumeration devemos realizar o "valueOf(...)".


Persistindo sem o RFWDAO

Ao persistir o RFWVO sem o RFWDAO, será necessário identificar como o seu sistema salva as enumerações. Embora existam diversas maneiras de se resolver, se seguir o método do RFWDAO, em que as enumerations são salvas somente pelos seus nomes, ao recuperar o nome do banco de dados e utilizar o ".valueOf()" a operação falhará, já que não sabemos de qual enumeration a unidade pertence.

Para resolver isso o MeasureRuler tem o seguinte método:

MeasureRuler.valueOf(...);

Este método identifica a unidade pelo nome, entre todas as dimensões existentes no MeasureRuler.


Stop 256.png
Unidades de Medidas Iguais
Por conta de termos várias unidades de medidas de dimensões diferentes representadas em enumerations diferentes, o Java permitirá que tenhamos uma unidade de medida "X" tanto em VolumeUnit quanto em AreaUnit. Embora o Java não tenha problemas para compilar esse código, ao ser persistido no banco de dados (salvo apenas o NAME da enumeration), a recuperação do objeto é baseada apenas no nome da enumeration. Isso fará com que seja sempre retornada pela primeira enumeration que o código procura.

Para evitar esse problemas as unidades de medidas devem sempre ter nomes diferentes mesmo que em dimensões distintas. Embora não conheça nenhuma unidade de medida que tenha o mesmo o nome e represente coisas diferentes, é bom que o DEV tenha ciência dessa situação.

Utilização da Régua

Para realizar a conversão das unidades de medidas devemos focar nos métodos .convertTo(...) da classe MeasureRuler. Há métodos simples utilizados para conversão dentro da mesma dimensão (sem utilização de equivalências) até métodos completos com a entrada de equivalências e definição da precisão de casas decimais.

Exemplos de Utilização

Veja alguns exemplos de utilização da MeasureRuler:

Java 256.png Conversão de Unidade de Medida dentro da Mesma Dimensão
  // Converte 1000ml em Litros, retornará um BigDecimal com o valor de 1.000
  MeasureRuler.convertTo(new BigDecimal("1000"), VolumeUnit.MILLILITER, VolumeUnit.LITER);

  // Converte 1000ml em Litros, mas dessa vez retornará com a precisão de 6 casas decimais.
  MeasureRuler.convertTo(new BigDecimal("1000"), VolumeUnit.MILLILITER, VolumeUnit.LITER, 6);

  //  Converte 1000g em Kilogramas, com uma precisão de 6 casas decimais, retornará o valor 1.000000
  MeasureRuler.convertTo(new BigDecimal("1000"), WeightUnit.GRAM, WeightUnit.KILOGRAM, 6);


Para converter entre diferentes dimensões (grandezas de medidas diferentes), vamos primeiro estabelecer uma regra de equivalência entre as grandezas, podendo ser feita com qualquer unidade de medida da grandeza.

Vejamos um exemplo, imagine um sistema de marcenaria que precise cadastrar uma chapa de madeira utilizada para móveis. No estoque e durante o processo de compra, referenciamos o item por unidades, pois fica mais fácil de fazer o pedido e comparar preços. Mas no momento de calcular o frete, precisamos saber qual o peso de cada chapa, ou qual o peso final do móvel produzido, de acordo com a "quantidade de chapa" (medida em metros quadrados (área)) que foi recortado e utilizado. Para ter todas essas informações precisamos estabelecer a relação entre as grandezas Unidades, Massa (Peso) e Área.

Imagine que após verificar o produto, descobrimos que a chama tem medida de 2m x 1,8m (=3,6m²), e que ela pesa 76Kg. Assim, montamos nossos dados de equivalência:


Java 256.png Criando Regras de Equivalência
  // Regras de Equivalência
  MeasureRulerEquivalence eqVO = new MeasureRulerEquivalence();
  eqVO.getMeasureUnitHash().put(UnitUnit.UNIT, new BigDecimal("1")); // Definimos que cada 1 Unidade...
  eqVO.getMeasureUnitHash().put(WeightUnit.KILOGRAM, new BigDecimal("76")); // equivale a 76Kg...
  eqVO.getMeasureUnitHash().put(AreaUnit.SQUAREMETER, new BigDecimal("3.6")); // e a 3,6m²


Com as regras de equivalência o 'MeasureRuler conseguirá converter unidades conforme a necessidade. Vamos imaginar que o marceneiro precisa saber quantas chapas vamos precisar para cobrir uma área de 40m². Assim convertemos na régua:


Java 256.png Convertendo Entre as Dimensões
  // Chamamos a MeasureRuler, mas agora passando as regras de conversão
  BigDecimal v = MeasureRuler.convertTo(eqVO, new BigDecimal("40"), AreaUnit.SQUAREMETER, UnitUnit.UNIT, 6);

  // o Valor de v será equivalente a 11.111111, com 6 casas decimais de precisão, conforme solicitado


Unidades de Medidas Personalizadas

O MeasureRuler permite que o usuário crie suas próprias unidades de medidas bastando apenas definir um nome e um símbolo em uma classe que estenda a interface MeasureUnit. Depois, para que a unidade de medida se torne funcional basta adiciona-la a régua de equivalências como no exemplo anterior.

Imagine que o marceneiro do exemplo anterior, é de uma cidade esquisita e que lá existe uma unidade de medida "XYZ", utilizada localmente, cujo símbolo é "Xz" e que representa 7 Unidade. Para adicionar essa nova unidade na nossa equivalência bastaria criar um objeto implementando a interface MeasureUnit, como dito anteriormente. Veja o exemplo:


Java 256.png Unidade de Medida Personalizada
  // Mesma régua de equivalências do exemplo anterior
  MeasureRulerEquivalence eqVO = new MeasureRulerEquivalence();
  eqVO.getMeasureUnitHash().put(UnitUnit.UNIT, new BigDecimal("1"));
  eqVO.getMeasureUnitHash().put(WeightUnit.KILOGRAM, new BigDecimal("76"));
  eqVO.getMeasureUnitHash().put(AreaUnit.SQUAREMETER, new BigDecimal("3.6"));

  // Vamos utilizar a classe CustomMeasureUnitGeneric que implementa a interface necessária, para criar nossa unidade de medida personalizada
  CustomMeasureUnitGeneric xyz = new CustomMeasureUnitGeneric("XYZ", "Xz");

  // Agora incluímos nossa unidade de medida com o peso de 7 (pois é 7Xz para 1 Unidade)
  eqVO.getMeasureUnitHash().put(xyz, new BigDecimal("7"));


Note que o peso foi 7 porque nossa régua está criada com peso de 1 em unidades. Se nossa equivalência fosse 7Xz para 2 Unidades, teríamos que trocar o peso de 7 para 3,5Xz. Quando montamos a régua de equivalência temos que colocar os pesos que sejam compatíveis. No nosso exemplo, o código seria lido como se fosse a seguinte igualdade:

1 Unidade = 76Kg = 3,6m² = 7Xz


Equivalências Despareadas

Este é um recurso criado apenas para simplificar e permitir que o MeasureRuler faça os cálculos pra você no momento de adicionar as equivalências desconectadas.

Por exemplo, imagine que você tenha as seguinte igualdades de equivalência:

1 Unidade = 36g
2m² = 12,4Kg

Nessa situação teríamos que calcular as igualdade de maneira que se tornassem todas proporcionais, unificando a unidade de medida de Massa em "g" ou em "Kg" e recalculando a razão da outra unidade de medida. Até termos algo como:

1 Unidade = 36g => 0,001 Unidade = 0,036Kg => 0,3444444 Unidades = 12,4Kg
2m² = 12,4Kg

para que então possamos estabelecer a equivalência entre todos:

0,3444444 Unidades = 12,4Kg = 2m²


Para evitar esse trabalho todo externo a interface MeasureRulerEquivalenceInterface tem um método "default" chamado addComparativeEquivalence que permite adicionar essas referências descasadas diretamente. Vejamos o código no nosso exemplo acima:


Java 256.png Unidade de Medida Descasada
  // Criamos a régua e incluímos nossa primeira equivalência ligando duas dimensões
  MeasureRulerEquivalence eqVO = new MeasureRulerEquivalence();
  eqVO.getMeasureUnitHash().put(UnitUnit.UNIT, new BigDecimal("1"));
  eqVO.getMeasureUnitHash().put(WeightUnit.GRAM, new BigDecimal("36"));

  // Agora já temos Unidades e Massa na régua de equivalência, podemos adicionar outra dimensão utilizando uma dessas referência
  eqVO.addComparativeEquivalence(new BigDecimal("2"), AreaUnit.SQUAREMETER, new BigDecimal("12.4"), WeightUnit.KILOGRAM);


Internamente o método fará a conversão e estabelecerá os pesos corretos para conversão.


Persistindo as Unidades de Medidas Personalizadas

Cada sistema tem autonomia para tratar a persistência como preferir, mas a metodologia utilizada pelo RFW, e que é praticada pelo MeasureUnitDAOCOnverter quando utilizado o RFWDAO é a seguinte:

Primeiro vamos relembrar que a MeasureUnit padrão é uma enumeration, e que o RFW mantém as enumeration com o limite máximo de 50 caracteres. Inclusive sugerindo que o campo no banco seja um varchar(50).

Segundo, a unidade de medida personalizada é composta apenas de um nome e um símbolo.

Com essas diretrizes, a solução implementada foi, sempre que a MeasureUnit recebida para persistência for uma CustomMeasureUnit, será montada uma String no formato:

"#" + value.getSymbol() + "|" + value.name()

Utilizamos o primeiro carácter "#" para identificar que se trata de uma serialização de CustomMeasureUnit, e um "|" para separar o Símbolo do nome. Ao reler o conteúdo no banco de dados, detectamos o primeiro carácter, se encontramos o "#" montamos uma CustomMeasureUnit com o objeto CustomMeasureUnitGeneric fazendo o parser da serialização anterior.


Note 64.png
Objeto da Desserialização
Note que se a aplicação utilizou seu próprio objeto para implementar a interface CustomMeasureUnit o MeasureUnitDAOConverter não é capaz de retornar um objeto personalizado.

Como alternativa você pode implementar seu próprio converter e retornar seu objeto necessário. Ou, ainda, converter o objeto retornado quando e se for necessário. Se apenas forem necessários os métodos da interface, ele pode ser mantido.


Note 64.png
Limite dos Tamanhos
Seguindo essa metodologia de serializar o objeto personalizado no campo de 50 caracteres destinado a enumeration, temos que lembrar que o limite de Nome da Unidade de Medida + Simbolo será de 48, pois temos mais 2 caracteres de sinalização.

Esse tamanho precisa ser validado em alguma parte do sistema caso sejam estabelecidos esses parâmetros. O MeasureRuler não inclui essa validação no seu código pois ela pode ser diferente para cada sistema.

Validação da Régua de Equivalência

É importante tomar cuidado com as informações fornecidas dentro da régua de equivalências para que não sejam incoerentes.


Stop 256.png
Informações Redundantes
Só devemos ter uma unidade de medida de cada dimensão. Incluir na Hash múltiplas informações da mesma dimensão é desnecessário, e podem resultar em resultados "aleatórios" se elas não forem coerentes.

Exemplos:

Incluir 1Kg, 1000g e 50Unidades - A hash aceitará a unidade de medida KILOGRAM e GRAM, mas a informação é redundante, mas não causará nenhum problema.

Incluir 1Kg, 500g e 50Unidades - Informar que 1Kg é equivalente à 500g é uma informação incoerente. Ao procurar as equivalências para converter Unidades em Massa, o MeasureRuler pode hora utilizar a informação de 1Kg - 50 Unidades, hora utilizar 500g - 50Unidades. Dependendo da informação que encontrar primeiro na Hash o resultado será diferente.



A classe MeasureRuller contém um método de validação validateMeasureRulerEquivalence() para garantir que as informações da Hash de equivalências não estão redundantes ou incoerentes.