Os métodos de uma classe devem chamar seus próprios getters e setters?

51

Onde eu trabalho, vejo muitas aulas que fazem coisas assim:

public class ClassThatCallsItsOwnGettersAndSetters {

    private String field;

    public String getField() {
        return field;
    }

    public void setField(String field) {
        this.field = field;
    }

    public void methodWithLogic() {
        setField("value");
        //do stuff
        String localField = getField();
        //do stuff with "localField"
    }
}

Se eu escrevesse isso do zero, eu teria escrito o methodWithLogic() desta forma:

public class ClassThatUsesItsOwnFields {

    private String field;

    public String getField() {
        return field;
    }

    public void setField(String field) {
        this.field = field;
    }

    public void methodWithLogic() {
        field = "value";
        //do stuff            
        //do stuff with "field"
    }
}

Eu sinto que quando a classe chama seus próprios getters e setters, isso torna o código mais difícil de ler. Para mim, quase implica que a lógica complexa está acontecendo na chamada do método, embora no nosso caso quase nunca seja. Quando estou depurando algum código desconhecido, quem pode dizer que o bug não é algum efeito colateral nesse método? Em outras palavras, isso me faz ter muitas viagens paralelas na jornada de entender o código.

Existem benefícios para o primeiro método? O primeiro método é realmente melhor?

    
por Daniel Kaplan 04.01.2013 / 21:20
fonte

9 respostas

46

Não vou dizer qual é melhor ou pior, porque isso depende em parte da sua situação (na minha opinião). Mas considere que seus getters e setters podem alterar a implementação posteriormente, e ignorá-los ignoraria essa lógica.

Por exemplo, o que acontece se você adicionar um sinalizador "dirty" a alguns campos de setter mais tarde? Ao chamar seus setters em seu código interno, você definirá o sinalizador sujo sem alterar nenhum outro código. Em muitas situações isso seria bom.

    
por 04.01.2013 / 21:34
fonte
31

Chamar o setter diretamente não é, por si só, um problema. A questão realmente deveria ser: por que nosso código tem setters em todos os lugares?

As classes mutáveis são um jogo perigoso, especialmente quando a própria classe gerencia seu próprio estado. Considere quantos desses setters realmente precisam existir. Quantas poderiam ser definidas no construtor e, em seguida, ficar totalmente encapsuladas pela própria classe?

Se o campo deve ser configurável externamente, então pergunte a si mesmo se o método com lógica deve estar lá. Sua classe é realmente apenas uma classe de dados / estado? Esta classe tem mais de uma responsabilidade?

Não me entenda mal, haverá casos em que isso é bom. Eu não estou dizendo que você deve eliminar setters em classes com lógica inteiramente. Mas estas devem ser a exceção, não a regra. E, nesses poucos casos, deve ser óbvio qual acessar diretamente.

    
por 04.01.2013 / 21:49
fonte
9

Sim, os métodos da sua turma devem chamar os getters e setters. O ponto inteiro, por escrito, getters e setters é a prova do futuro. Você poderia transformar cada propriedade em um campo e expor diretamente os dados aos usuários da classe. O motivo pelo qual você constrói os getters e setters não é necessariamente porque há uma lógica complexa agora, mas para que a interface não seja quebrada no futuro, se você precisar adicioná-la.

    
por 04.01.2013 / 21:33
fonte
6

Para responder às suas perguntas em uma palavra, sim.

Ter uma classe chamada getters e setters adiciona extensibilidade e fornece uma base melhor para códigos futuros.

Digamos que você tenha algo assim:

public class Vehicle
{
    private int year;
    private String make;

    public Vehicle(int year, String make)
    {
        setYear(year);
        setMake(make);
    }

    public void setYear(int year)
    {
        this.year = year;
    }

    public void setMake(String make)
    {
        this.make = make;
    }
}

Chamar os setters por ano e fazer atualmente não pode adicionar nenhuma funcionalidade, mas e se você quisesse adicionar algo como validação de entrada para os setters?

public class Vehicle
{
    private int year;
    private String make;

    public Vehicle(int year, String make)
    {
        setYear(year);
        setMake(make);
    }

    public void setYear(int year)
    {
        if(year > 0)
        {
            this.year = year;
        }
        else
        {
            System.out.println(year + " is not a valid year!");
        }
    }

    public void setMake(String make)
    {
        this.make = make;
    }
}
    
por 05.01.2013 / 08:48
fonte
5

Uma coisa que não foi mencionada é que getter e setters (como todos os métodos) são virtuais em Java. Isso adiciona outro recurso a sempre usá-los em seu código. Outro usuário poderia estender sua turma, sobrescrevendo seus getters e setters. Sua classe base, então, estaria usando os dados da subclasse em vez da sua própria. Em um idioma em que você marca explicitamente as funções virtuais, isso é muito mais útil, pois é possível prever e declarar com quais funções isso pode ser feito. Em Java, isso é algo que você sempre deve estar ciente. Se é um comportamento desejado, então usá-los em seu código é uma coisa boa, caso contrário não muito.

    
por 09.01.2013 / 15:30
fonte
3

Se você está tentando realizar algo que é fornecido pela interface pública, use os getters / setters.

No entanto, como proprietário / desenvolvedor da turma, você tem permissão para acessar as seções particulares do seu código (de dentro da turma, é claro), mas também é responsável por atenuar os perigos.

Então, talvez você tenha um getter que percorra uma lista interna e deseje obter o valor atual sem incrementar o iterador. Neste caso, use a variável privada.

public class MyClass
{
    private int i;
    private List<string> list;
    public string getNextString()
    {
        i++;
        return list[i];
    }

    private void getString()
    {
        // Do not increment
        string currentString = list[i];

        // Increment
        string nextString = getNextString();
    }
}
    
por 04.01.2013 / 21:46
fonte
1

Sim. Os getters e setters representam o estado, portanto, revise essa questão - você quer ter que controlar várias maneiras de alterar um estado de objetos da mesma maneira, a menos que seja necessário?

Quanto menos coisas você tiver para acompanhar, melhor - é por isso que objetos imutáveis são mais fáceis de lidar.

Considere, não há nada que impeça você de ter um campo público e um getter / setter público - mas o que você ganharia?

Pode ser desejável ou mesmo necessário acessar diretamente o campo por uma ou mais razões, você não deve se esquivar disso se acontecer. Mas você só deve fazê-lo se houver um benefício definido em fazê-lo.

    
por 05.01.2013 / 09:58
fonte
1

Ambos os métodos têm seus casos de uso. Como o setter público mantém o valor do campo (e / ou valores associados) consistente, você deve usar o setter quando a lógica do seu método não interferir com essa lógica de consistência. Se você acabou de definir sua "propriedade", use setter. Por outro lado, há situações em que você precisa de acesso direto a alguns campos, por exemplo, operações em massa com configuração pesada ou operações em que o conceito de setter é muito simples.

É sua responsabilidade manter as coisas consistentes. Setter faz isso por definição, mas não pode cobrir casos complexos.

    
por 05.01.2013 / 19:18
fonte
1

Eu diria Não ..

Se seus getters / setters apenas pegarem e configurarem (sem inicialização lenta, sem verificações, etc), então use suas variáveis. Se no futuro você mudar seus getters / setters, você pode muito bem alterar seu methodWithLogic() (porque é a sua classe que está mudando) e você pode chamar um getter / setter em vez de uma atribuição direta. Você pode documentar esta chamada para o getter / setter (como será estranho chamar um getter / setter quando o resto do seu código de classe estiver usando diretamente a variável).

A JVM irá enviar chamadas frequentes para getters / setters. Então, nunca é um problema de desempenho. O ganho de usar variáveis é a legibilidade e IMHO, eu iria para ele.

Espero que isso ajude ..

    
por 09.01.2013 / 15:06
fonte