Solucionado (ver solução)
Solucionado
(ver solução)
3
respostas

Usar o tipo "ReadonlyArray" como retorno no método "list" não me impede de mudar a lista.

Basta fazer assim

(this.negociacoes.list() as Array<Negociacao>).pop();

Neste caso para mim o tipo ReadonlyArray se torna inútil para encapsular uma propriedade. Apenas a clonagem via spread operator se mostrou eficaz.

3 respostas

Olá, Pedro, tudo bem?

Muito interessante a sua observação! Isso me fez pensar um pouco e elenquei vantagens e desvantagens de cada abordagem.

Usando spread operator


Como você pontuou, usando o spread operator nós garantimos que a referência do array não seja acessada. Porém, em NegociacaoController, quando digitamos this.negociacoes.lista(), mesmo que o pop() não modifique o array privado negociacoes da classe Negociacoes, ele ainda aparece como sugestão no autocomplete.

Então há a possibilidade de um(a) desenvolvedor(a) com pouco conhecimento do projeto utilizar esse método e não entender porque não está funcionando.

Alterando o tipo da lista() para ReadonlyArray


Com essa abordagem, os métodos de escrita de arrays nem mesmo aparecem ou funcionam, então isso já pode ser uma dica para a pessoa que for trabalhar no projeto de que não podemos alterar esse array (além do tipo ReadonlyArray ser semântico). Mas novamente, como você disse, nada impede a pessoa de escrever this.negociacoes.list() as Array<Negociacao>, mas na minha visão, a pessoa que souber fazer isso deve ter mais conhecimento da linguagem e provavelmente sabe que é algo mais perigoso de se fazer.

Ainda assim, não é garantido que o array não possa ser modificado.

Elencados esses pontos, acredito que será uma escolha do(a) desenvolvedor(a) qual abordagem utilizar.

Espero ter ajudado! Abraços e bons estudos :)

Olá Antônio, ótimas pontuações.

Quando se trata de encapsulamento eu sempre gosto de pensar como se o desenvolvedor que for consumir minha função ou classe não pudesse ver o que acontece lá dentro. Eu posso estar escrevendo por exemplo uma biblioteca que será publicada.

Então partindo deste princípio pra mim a abordagem usando spread operator é a mais adequada para a maioria dos casos, pois assim o desenvolvedor do outro lado não conseguirá "quebrar" minha implementação.

E somando a sua sugestão de que o programador pode não ter muito conhecimento do projeto, talvez nomear o método de cloneLista() em vez somente lista()pudesse auxiliar.

solução!

Olá novamente, Pedro!

Na verdade acabei de ter uma ideia, nada nos impede de unir as duas abordagens! Assim:

  lista(): ReadonlyArray<Negociacao> {
    return [...this.negociacoes];
  }

Assim, a propriedade privada negociacoes não corre o risco de ser alterada, e os métodos de alteração do array também não serão sugeridos no autocomplete.

E somando a sua sugestão de que o programador pode não ter muito conhecimento do projeto, talvez nomear o método de cloneLista() em vez somente lista()pudesse auxiliar.

Essa também é uma ótima ideia, assim a pessoa terá uma dica melhor de porque os métodos de alteração não alteram o array original.

Bons estudos!