Mudanças entre as edições de "MeasureRuler"
(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 | 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"> | |||
// 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")); | |||
</syntaxhighlight>}} | |||
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: | |||
<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: | ||
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.
![]() |
|
Para definir um atributo no VO que seja do tipo MeasureUnit devemos ter algo como:
![]() |
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.
![]() |
|
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:
![]() |
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:
![]() |
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:
![]() |
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:
![]() |
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:
![]() |
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.
![]() |
|
![]() |
|
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.
![]() |
|
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.