11.5. Atributos e métodos de classe (static)

Os atributos que criámos até agora denominam-se "de instância" pois cada instância da classe tem esses atributos; os seus valores, em cada instante, definem o "estado" do objeto.

De igual forma, os métodos que criámos até agora denominam-se "de instância" pois:

Há casos em que precisamos de definir um valor que está relacionado com os objetos duma dada classe mas que é igual para todos. Também há casos em que precisamos de definir um método numa classe que não depende das características específicas de cada objeto. Para estes casos queremos criar atributos e métodos de classe.

 

11.5.1. Atributos de classe

Não queremos usar literais "espalhados" pelos métodos das nossas classes pois isso dificulta não só a compreensão (sobre o que representam) mas também uma futura alteração desses valores no texto dos programas que os usam.

No nosso caso, queremos evitar escrever diretamente os valores 5, 0 e 10 na classe Jogo, tanto no corpo dos métodos como na documentação. Estes são os valores do número máximo de jogadores e dos valores mínimo e máximo de pontuação por jogada, respetivamente.

Vamos criar mais três atributos e atribuir-lhes estes valores no construtor? Não propriamente. Se não, vejamos:

Basta defini-los como atributos de classe

Um atributo de classe

 

11.5.2. Constantes

Além de querermos defini-los como atributos de classe (static) também queremos que os seus valores se mantenham constantes e não possam ser alterados durante a vida de um objeto deste tipo.

Para indicar que são constantes usamos a palavra reservada final e atribuímos-lhes um valor inicial (que não mudará).

Por convenção, os nomes das constantes escrevem-se todos em maiúsculas e com _ como separador de palavras.

11.5.3. Atributos public

Queremos ainda que as classes cliente de Jogo possam conhecer estes valores.

Declaramo-los então como public – como são constantes, não há problema em serem public pois nenhuma classe cliente conseguirá alterar o seu valor.

11.5.4. Exemplificando

Acrescentamos estes atributos de classe constantes à nossa classe e alteramos os pontos onde eram usados estes valores, tanto internamente como na documentação, para passarem a referir estas constantes:

Segue-se um exemplo de utilização destas constantes. As seguintes instruções numa qualquer classe cliente de Jogo,

pedem ao utilizador um valor entre Jogo.MIN_PONTUACAO_JOGADA e Jogo.MAX_PONTUACAO_JOGADA e invocam o método que permite registar nova pontuação para um jogador.

Esta classe respeita a pré-condição do método registarPontosJogada, pois este só é invocado quando há a certeza de que o valor para o parâmetro pontuacao está no intervalo exigido pela pré-condição.

Enquanto o utilizador introduzir um valor fora do intervalo [0,10], verá a mensagem "insira valor entre 0 e 10" no ecrã. Logo que introduza um valor no intervalo requerido, o ciclo termina e o método registarPontosJogada é invocado.

 

11.5.5. Métodos de classe

Suponhamos que queremos ter um segundo construtor na classe Jogo que permita registar todos os jogadores no momento de criação do jogo, em vez de criar um jogo e ir adicionando jogador a jogador como temos feito.

Esse construtor poderia ter a seguinte forma:

Na pré-condição gostaríamos de exprimir uma série de restrições acerca do array participantes como, por exemplo, que tem que ter um ou mais elementos mas que não pode ter mais do que MAX_JOGADORES elementos e que não pode conter nenhum elemento repetido.

O ideal seria ter um método na classe Jogo que, dado um array de strings, permitisse verificar se esse array satifaz as restrições acima. Este método – chamemos-lhe dadosValidos – podia então ser invocado em qualquer classe cliente de Jogo para verificar se um dado array de strings pode ser usado para criar um jogo.

Se este método dadosValidos fosse um método de instância, teríamos que o invocar sobre um objeto do tipo Jogo. Mas que objeto seria este? Nós queremos saber se o array de strings é válido precisamente para o podermos usar para criar um jogo! Logo, não faz sentido ser invocado sobre uma instância de Jogo.

Este método tem ser um método de classe, ou seja, ele deve ser invocado sobre a classe Jogo e não sobre uma qualquer instância em particular, pois o resultado do método não depende de maneira nenhuma das características particulares de nenhum objeto.

Indicamos que é de classe usando a palavra static.

Para invocar um método de classe, o alvo da invocação é a classe, como exemplificado nestas instruções numa qualquer classe cliente de Jogo:

 

 


 

Anterior: 11.4. Outros métodos relativos a um dado jogador do jogo

Seguinte: 11.6. O método toString na classe Jogo