Matias Leidemer
Published on

Implementando Lazy initialization

In computer programming, lazy initialization is the tactic of delaying the creation of an object, the calculation of a value, or some other expensive process until the first time it is needed. Wikipédia.

Inspirado pelo ótimo 20,000 Leagues Under ActiveRecord, decidi tentar implementar uma classe que utiliza a tática de lazy initialization para postergar um processamento, teoricamente, custoso. A idéia, tal qual acontece com o ActiveRecord (explicado no post linkado) é ir adicionando condições à um objeto para, posteriormente, executar uma tarefa.

Para exemplificar, criei a LazyCalculator. Uma calculatora que armazena as condições (por hora, apenas adição e subtração) e, quando solicitada, calcula o resultado.

require_relative "lazy_calculator"

calculator = LazyCalculator.new
=> #<LazyCalculator:0x007fbbe31a7ee8 @numbers=[], @operations=[]>

calculator.plus(5)
=> #<LazyCalculator:0x007fbbe31a7ee8 @numbers=[5], @operations=[:+]>

calculator.minus(2)
=> #<LazyCalculator:0x007fbbe31a7ee8 @numbers=[5, 2], @operations=[:+, :-]>

irb(main):006:0> calculator.calc
=> 3

Obviamente a complexidade da LazyCalculator nem se compara com a do ActiveRecord. Mas acho que a idéia fica bem clara nos exemplos acima. Observe que os métodos plus e minus retornam a instância do própria objeto. Isso possibilita o encadeamento de vários métodos (method chaining):

calculator = LazyCalculator.new

calculator.plus(5).minus(1).minus(9).plus(1).calc
=> -3

Também fica bem claro como o método calc é postergado até o momento em que é realmente necessário. Quando executado, ele verifica os valores e operações que já existem no objeto atual e realiza o cálculo.

Eu já havia observado esse comportamento no ActiveRecord, mas ainda não havia tirado um tempo para dar uma olhada com mais calma. Esse tipo de solução me agrada, simples e efetiva, utilize em seu código sempre que parecer conveniente.