O que fazer com campos privados com getters e setters em Java [duplicado]

5

Quando os Justificadores e Setters são justificados é uma excelente pergunta que concentra-se em usar getters e setters como parte da interface externa.

O que estou lutando é ... ter getters e setters agora tem várias maneiras de atualizar o estado do objeto, já que os campos privados podem ser atualizados diretamente, ignorando o setter ou podem ser atualizados pelo setter.

Veja o exemplo abaixo ... _size é o campo privado e tem dois métodos getSize() e setSize(int size) . Se incrementar _size for codificado como o método increment , tudo ficará bem. Por outro lado, usar increment2 pode colocar Order em um estado ilegal.

Existe uma maneira de impedir que os desenvolvedores ignorem acidentalmente o getter / setter e usem os campos privados diretamente? Se não, qual convenção deve ser usada para garantir que o objeto nunca seja colocado em um estado inválido?

public class Order {

    private int _size = 0;

    public int getSize() {
        return _size;
    }

    public void setSize(int size) { 
        if (_size < 0)
             throw IllegalArgumentException("...")

        _size = size; 
    }

    public void increment(int increment) {
        setSize(getSize() + increment);
    }

    public void increment2(int increment) {
        _size = _size + increment;
    }



 }
    
por Dakotah North 22.05.2011 / 20:11
fonte

2 respostas

2

Em primeiro lugar, você geralmente não deve ter getters e setters públicos. Um objeto deve fornecer uma interface de nível superior que não exija que objetos externos alterem, mesmo com a validação, o estado interno do objeto. Dessa forma, se o seu objeto mudar, outros objetos também não precisarão mudar.

Por esse motivo, seu método de incremento é uma boa ideia, enquanto sua função setSize não é. Você simplesmente não deveria estar fornecendo uma interface de baixo nível.

Em segundo lugar, o objeto inteiro é responsável por manter o estado interno. Em seu caso simples acima, eu provavelmente escreveria:

void increment(int amount)
{
     if(amount < 0) throw new InvalidArgumentError("amount must not be negative");
     _size += amount;
}

Eu acho que detectar argumentos de métodos inválidos é melhor do que verificar a invalidação de estado. Dessa forma, sua interface externa se concentra no que você pode fazer com um objeto, em vez de como evitar a produção de um estado interno inválido.

Em terceiro lugar, pode fazer sentido validar seu objeto para garantir que nenhum bug tenha introduzido inconsistências nele. No entanto, a melhor maneira de realizar essa tarefa depende realmente das ferramentas que a sua linguagem lhe oferece. No entanto, acho que tentar usar setters para isso tem problemas.

O uso de setters introduz muitos códigos adicionais para chamá-los. Todo o seu código fica difícil de ler como resultado.

Às vezes, invariantes dependem de dois valores. Por exemplo, um C ++ std :: vector deve ter sua capacidade () > = size (). Se você tentar proteger o setSize () e setCapacity (), qual deles verifica se o tamanho é maior?

Além disso, objetos muitas vezes se tornam inválidos durante o processamento da lógica interna antes de se tornarem válidos novamente. Um setter verifica o objeto em todas as atribuições, mas você realmente quer que a verificação seja concluída após o método chamado publicamente.

    
por 22.05.2011 / 22:44
fonte
6

Os getters e setters são para usuários externos da sua API

É claro que uma turma pode acessar seu estado interno e alterá-lo conforme necessário. Eles não precisam passar por um setter. O padrão é projetado como uma medida defensiva para usuários externos do seu código. Idealmente, o getter fornece um clone do estado interno e o setter fornece validação para garantir que o estado interno válido seja mantido.

    
por 22.05.2011 / 21:28
fonte