Criando uma classe
Doggie DadyEm torno do tema da criação de uma classe vamos apresentar mais componentes do IDE do Smalltalk.
Vamos criar uma classe que represente uma conta num banco. Faremos isto de forma simplista para não incorrer em detalhes muito complexos e irrelevantes para o nosso objetivo de mostrar o básico da linguagem e do ambiente de programação.
Nossa classe definirá que seus objetos são capazes de "memorizar" o saldo de cada conta. E que podemos fazer depósitos e retiradas em cada conta. O saldo evoluirá em função desses depósitos e retiradas.
O tratamento de erros será negligenciado para tornar o código mais simples e legível ao mesmo tempo evitando sobrecarregar a lição com muita informação que poderá ser absorvida depois em outras lições que tratem de temas mais específicos.
Continuaremos, por enquanto, privilegiando o uso do Playground como ferramenta didática e de fácil uso.
System Browser
O System Browser
é um browser que permite que você navegue pelas classes e códigos que você criou ou introduza novas classes e códigos associados a elas.
Componentes do System Browser
Acima temos a janela do System Browser
aberta com a classe Collection
selecionada.
Vemos as 6 seções ou painéis que compõem o System Browser
.
Da esquerda para a direita e de cima para baixo:
- Packages
- Classes
- Protocols
- Methods
- Code
- Critics
Vamos descrever sucintamente cada um.
Packages
Neste painel são mostrados os pacotes que existem no ambiente. No nosso exemplo está selecionado o pacote Collections-Abstract
. Um pacote contém várias classes.
Classes
Neste painel são mostradas as classes do pacote selecionado. No nosso exemplo selecionamos a classe Collection
.
Protocols
Neste painel basicamente são mostrados os protocolos que categorizam os métodos da classe selecionada.
Methods
Neste painel aparecem os métodos implementados na classe selecionada.
Code
Neste painel aparece código de acordo com o que está selecionado no conjunto dos 4 painéis acima. No nosso exemplo aparece o código que define a classe Collection
.
Critics
Neste painel aparecem mensagens de crítica informando sobre alguns problemas potenciais relativos à codificação.
Criando uma classe no System Browser
Antes de criar a classe devemos criar o pacote onde ela vai residir.
Criando o package e adicionando uma tag
Vamos criar o package-tag MyBank-Core
.
Clique com o botão direito em qualquer ponto do painel Packages
para obter o menu de contexto e selecione o submenu New package
.
Entre o nome do pacote.
Use novamente o menu de contexto para definir uma tag.
Logo abaixo do painel que mostra os pacotes (packages
) há dois radio buttons: All Packages
e Scoped View
. Selecione Scoped View
.
Criando a classe
Expanda o pacote Bank para que a tag Core
apareça.
No painel Code
você vê um template
para criação de uma classe no package-tag Bank-Core
. O template é uma expressão do Smalltalk que cria uma classe. É uma expressão como outra qualquer do Smalltalk. Repetimos a expressão abaixo:
Object subclass: #NameOfSubclass instanceVariableNames: '' classVariableNames: '' package: 'MyBank-Core'
Vamos modificar a expressão para que ela crie a classe Account
.
Cuidado para não remover o#
. O argumento dessa expressão que representa o nome da classe deve ser um símbolo (Symbol
) (Veja a lição Conhecendo alguns objetos básicos).
Agora vamos criar a nossa classe, o que fazemos através do submenu Accept
do menu de contexto (que aparece ao clicar com o botão direito do mouse).
E a classe é criada.
A expressão abaixo, que cria a classeAccount
, poderia ser avaliada, por exemplo, no Playground usandoDo it
. E a classe seria criada da mesma forma.
Object subclass: #Account instanceVariableNames: '' classVariableNames: '' package: 'MyBank-Core'
Definindo variáveis de instância
Vamos definir a variável de instância balance
. Para isso edite a expressão que cria a classe conforme mostrado abaixo e use o submenu Accept
como fez antes. As variáveis de instância são criadas através do argumento de instanceVariableNames:
.
Abaixo do painel que apelidamos de Protocols
selecione o radio button Vars
. As variáveis de instância da classe vão aparecer em vez da lista de protocolos (protocols
). Constate que balance
aparece.
Variável de instância é parte da estrutura que já mencionamos que uma classe define e que todas as suas instâncias vão ter como recurso de armazenagem do seu estado. No nosso caso significa que a classe ao criar uma instância, com a expressãoAccount new
, por exemplo, vai prover o objeto criado de um local para armazenar o valor da variável, no caso o saldo da conta (balance
).
As variáveis de instância são privadas. Quem usa um objeto não tem acesso a uma variável de instância diretamente mas somente através dos métodos.
Definindo métodos de instância
Abaixo dos 4 painéis temos as abas Comment
, Account
e + Inst. side method
. Selecione a aba + Inst. side method
. Verá então o template para a forma como um método deve ser escrito.
O template tem partes obrigatórias e outras opcionais. Na primeira linha colocamos a assinatura do método que descreve o seletor da mensagem e os parâmetros que deverão ser passados como argumentos na mensagem. É a única parte obrigatória.
As linhas seguintes com textos entre "
são comentários e não tem nenhum efeito na execução e são usados com fins de documentação.
Mais abaixo temos uma declaração de variáveis locais entre |
.
E finalmente o código que define como a mensagem com o seletor que coincide com a assinatura do método vai ser respondida com um efeito colateral (opcional) e o valor de retorno.
Vamos criar três métodos para a classe Account
: balance
, deposit:
e withdraw:
.
O nosso método balance
é executado quando uma instância da classe Account
recebe a mensagem unária balance
.
Valor de retorno de um método
O valor de retorno é especificado após o ˆ
. Caso seja omitido fica implicito que o valor de retorno é o próprio objeto (self
*).
* self
é uma pseudo-variável e palavra reservada que referencia o objeto que é o receptor da mensagem que acionou o método.
Criando o método balance
Os métodos são públicos. Isto é, fazem parte da interface pública dos objetos e podem ser acionados por mensagens enviadas ao objeto.
Se é o primeiro método que está criando na imagem o diálogo abaixo vai ser apresentado. Entre a sua identificação que será associada daqui em diante aos códigos que criar.
O método balance
deve aparecer na lista do painel que apelidamos de Methods
.
O métodobalance
é um método do tipoaccessor
. Especificamente é umgetter
. Um método para dar acesso de leitura a uma variável de instância específica. No caso a variável de instânciabalance
. A convenção e dar ao método o mesmo nome da variável a que dá acesso.
Criando o método deposit:
Faça de forma similar ao que fez quando criou o método balance
.
O método deposit:
responde a uma mensagem do tipo com palavras-chaves (keyword message
) e possui um argumento.
O métododeposit:
não possui uma linha contendoˆ
. Logo o retorno implícito éself
. O método é equivalente ao mostrado abaixo.
Criando o método withdraw:
O método initialize
Quando criamos uma instância de uma classe as variáveis de instância tem o valor nil
* por default.
* nil
é um valor que quando atribuido a uma variável significa que ela não referencia nenhum objeto. Quando uma variável que não contém nenhuma referência "recebe uma mensagem" acontece um erro.
Quando uma classe recebe a mensagem new
ela cria uma instância e invoca o método initialize
. Mas você tem que criar este método na sua classe se quiser fazer algumas inicializações. No caso da variável balance
vamos estabelecer que toda conta recém criada tenha balance
igual a zero
. Criamos então o método initialize
como abaixo mostrado.
Colocar a expressãosuper initialize
no método de instânciainitialize
é uma convenção que previne a necessidade de executar código herdado. No nosso caso é supérfluo. Voltaremos a isso quando discutirmosherança
.
Definindo métodos de classe
Vamos definir um método de classe que crie uma instância de Account
com um saldo inicial armazenado em balance
.
Clique no radio button Class side
para poder criar o método de classe no class side.
Selecione a aba + Class side method
. Vai ver um template igual ao que viu quando foi criar o método no instance side.
Vamos criar o método newWithInitialBalance:
.
Vamos analisar o código. Nele há o trecho
^ self new initialBalance: anAmount
O ˆ
no início indica que o resultado da expressão
self new initialBalance: anAmount
será retornado pelo método.
Há duas mensagens na expressão: new
e initialBalance:
.
A primeira mensagem, new
, tem como receptor self
.
Mas que objeto é referenciado por esse self
?
Se estivéssemos no instance side self
estaria referenciando o objeto que estivesse respondendo à mensagem.
Como estamos no class side o objeto que está respondendo à mensagem é a classe. E já vimos que as classes sabem responder à mensagem new
. Elas respondem a essa mensagem criando uma instância de si mesma e excutando o método initialize
. Logo o resultado de self new
é uma instância da classe Account
.
A segunda mensagem initialBalance:
é enviada a este objeto criado com self new
. Como esta mensagem é enviada a uma instância ela deve ser respondida por um método de instância. Como ainda não criamos o método initialBalance:
vamos fazê-lo no instance side.
Variável de classe
No momento não temos necessidade de criar uma variável de classe. Mas caso precisássemos de uma ela seria criada de forma semelhante à criação da variável de instância só que como o argumento declassVariableNames:
. As variáveis de classe valem para toda a classe e podem ser referenciadas nos código tanto noinstance side
como noclass side
. Mas não se preocupe agora com esses conceitos pois serão reintroduzidos quando houver necessidade de sua aplicação.
Variáveis de instância e métodos no class side
A classe é um objeto. Logo pode possuir também variáveis e métodos de instância que são definidos no seu class side
. Voltaremos a isso quando necessário.
Criando e usando objetos de uma classe
Vamos agora "exercitar" a nossa classe e suas instâncias usando o Playground (Veja Como abrir o Playground).
Usando o submenu Do it and go
do menu de contexto (acessado com o botão direito do mouse) na primeira expressão obtemos um inspector
aberto num painel do lado direito do Playground.
Vemos que a nossa variável de instância balance
está com o valor zero
que lhe foi atribuido no método initialize
em vez do valor default nil
.
Experimente inspecionar o resultado das outras expressões.
Troque a primeira expressão por account := Account newWithInitialBalance: 100
e inspecione os novos resultados.
Encerrando
Encerre salvando a imagem.