Em qualquer linguagem de programação existem geradores de números pseudo-aleatórios. Estes geradores são chamados assim pois os números não são de fato aleatórios, uma vez que é utilizada uma equação para calcular cada número gerado. Em Java, a classe Random
do pacote java.util
é uma das formas utilizadas para gerar tais números. No entanto, existem diferentes implementações destes geradores, cada uma com finalidades específicas ou diferentes níveis de qualidades em relação à aleatoriedade dos números gerados.
Bibliotecas como a Apache Commons Math fornecem, dentre outras funcionalidades, diversos geradores de números pseudo-aleatórios.
1. O problema
Existe uma grande variedade de implementações de tais geradores, cada implementação fornecendo uma interface diferente da outra. Para este projeto, observe o diagrama de classes abaixo.
Ele apresenta alguns métodos da classe Random
do pacote java.util
e da interface RealDistribution
da biblioteca Apache Commons Math. Algumas das classes que implementam esta última interface são NormalDistribution
e LogNormalDistribution
. Como podem ver, existem diferenças entre as classes/interfaces, tornando também diferente a forma de utilizar cada uma das implementações disponíveis.
A seguir são apresentados os detalhes das diferentes implementações.
1.1. Classe Random da plataforma Java
Na classe Random
temos os métodos nextDouble()
e doubles(long streamSize)
. Os dois podem ser utilizados para gerar números aleatórios. O primeiro gera um único número a cada vez que for chamado. O segundo gera um conjunto de números, cuja quantidade é definida pelo parâmetro streamSize
. Assim, chamando doubles(3)
, serão gerados 3 números aleatórios.
Adicionalmente, esta classe possui 2 construtores: um que não recebe parâmetro algum e outro que recebe uma seed
. A seed
(semente) é apenas um número que define o valor inicial do gerador. Se instanciarmos um gerador com a mesma seed
, a sequência de números gerados será sempre a mesma. Se alterarmos a seed
ou não informarmos uma, a cada vez que executarmos a aplicação, a sequência de números gerados será diferente.
1.2. Biblioteca Apache Commons Math
Já nas classes que implementam a interface RealDistribution
da biblioteca Apache Commons Math (como NormalDistribution
e LogNormalDistribution
), os métodos que retornam um número aleatório ou um conjunto de números são diferentes. Temos os métodos sample()
e sample(int sampleSize)
, semelhantes aos métodos da classe Random
, mas com nomes, tipos de parâmetro e retorno diferentes.
Por fim, nestas classes, se for preciso definir uma seed, isto não é feito por meio de um construtor, mas chamando o método reseedRandomGenerator(long seed)
.
2. O Desafio
Identifique qual padrão de projeto pode ser aplicado para uniformizar a interface das classes Random
do pacote java.util
e das classes que implementam a interface RealDistribution
da biblioteca Apache Commons Math. O padrão deve então permitir que a forma de utilizar qualquer destas classes seja a mesma.
Altere a aplicação de exemplo nesta pasta (que já inclui a dependência para a biblioteca Apache Commons Math no arquivo pom.xml) para aplicar o padrão de projeto adequado. Por fim, modifique a classe Principal
para utilizar as classes criadas para o padrão.
3. Detalhes de Implementação
Observe que os métodos sample(int sampleSize)
da interface RealDistribution
e doubles(long streamSize)
da classe Random
tem tipos de parâmetros e retorno diferentes. O primeiro retorna um vetor de double e o segundo retorna um objeto DoubleStream
.
Uma maneira de uniformizar tais métodos é fazer com que o segundo também retorne um vetor de double. O código para isto pode ser:
double[] numeros = random.doubles(10).toArray();
Neste exemplo, estamos chamando o método doubles()
, indicando que desejamos gerar 10 números aleatórios e convertendo de DoubleStream
para um vetor usando o método toArray()
.
Estamos padronizando fazendo os métodos retornarem vetores, pelo fato destes serem mais familiares que Streams (como é o caso do DoubleStream). Streams são mais modernos, seguros e flexíveis que vetores, mas vamos utilizar apenas vetores para simplificar.