Orientação a Objetos
====================

1. História da OO
-----------------

1963: Sketchpad
  - Editor gráfico que introduz o conceito de objeto
  - http://www.youtube.com/watch?v=mOZqRJzE8xg
  - http://pt.wikipedia.org/wiki/Sketchpad
1962-8: Simula
  - Linguagem para simulação, introduz o conceito de classes
  - http://pt.wikipedia.org/wiki/Sketchpad
1972-80: Smalltalk
  - Primeira linguagem OO pura, tudo em Smalltalk são
    objetos, instâncias de alguma *classe* que respondem
    a *mensagens*. As próprias classes são objetos!
  - http://pt.wikipedia.org/wiki/Smalltalk
  - http://www.youtube.com/watch?v=JLPiMl8XUKU
  - Implementação moderna: http://www.squeak.org
1995: Java
  - Sintaxe inspirada em C/C++
  - Modelo de execução mais parecido com o de Smalltalk
  
2. Dados primitivos
-------------------

São os átomos de dados da linguagem Java, usamos os tipos
abaixo como base para compor objetos mais complexos. Inteiros,
reais e booleanos são manipulados com os operadores pré-definidos
da linguagem (+, -, /, *, &&, ||, etc.), enquanto strings
são objetos manipulados através de chamadas a métodos, como
qualquer outro objeto (ainda vamos ver isso!), exceto pela
operação de concatenação (+).

* inteiros (int) - com sinal, 32 bits, ~-2e9 a ~2e9
  - operações como em C
  - 2, 5, 42, 1000000, -1
* "reais" (double) - ponto flutuante
  - operaçoes como em C
  - 1.23, 2.56e7, 0.0
* booleanos (boolean) - verdadeiro (true) e falso (false)
 - operações como os "booleanos" de C
 - && (e), || (ou), ! (negação)

* cadeias (String) - cadeias de símbolos
 - aspas duplas, códigos de escape (\n, \\, \t, \", ...)
 - "Olá Mundo", "Uma linha\nOutra linha",
 - "Ele disse, \"Olá!\""
 - uma operação pré-definida: concatenação (+)
 - "Olá " + "Mundo" = "Olá Mundo"
 - Concatenação não muda os operandos, mas cria uma nova string!
 - Strings não são modificáveis em Java: são *imutáveis*

* vetores (int[], double[], String[], int[][]...)
  - 'int[] foo' ao invés de 'int foo[]'
  - não existe 'int[5] foo'
  - criados com 'new int[5]'
  - depois de criados, acessados com [] como em C
  - não existe free ou delete, o espaço de um vetor é
    retomado por Java quando ele se torna *inacessível*

3. Classes
----------

Unidade de estruturação de um programa Java. No nível
mais básico funciona como uma *struct* de C, servindo
para agrupar diversos valores, chamados de *campos*,
em uma mesma entidade.

Os campos de uma classe podem ter qualquer tipo, inclusive
outras classes! A inicialização dos campos pode ser feita na
sua declaração, mas comumente é feita por um dos *construtores*
da classe. A função dos construtores é inicializar um objeto
recém-criado. Dentro de um construtor a variável *this* aponta
para o objeto que acabou de ser criado.

* Modelagem "Space Invaders"
* Classe Alien
  - Campos e construtor
  - Construtor *inicializa* um objeto recém-criado
  - Objetos criados com new: new Alien(10, 50)
  - Identidade de objetos (==) vs. "igualdade"
    Cada chamada a new cria um objeto distinto. O operador
    == só é true se os dois lados são o mesmo objeto. Em
    particular, new Alien(10, 50) == new Alien(10, 50) é
    false
  - Variáveis *apontam* para objetos
    Se a1 e a2 são variáveis do tipo Alien e faz-se
    a1 = a2 = new Alien(10, 50) então a1 == a2 será true,
    pois a1 e a2 estarão apontando para o mesmo objeto
* Classe Cor
  - Uma classe pode ter mais de um construtor, o construtor
    chamado vai depender do número e tipo dos argumentos
    passados na chamada para new
  - Campos podem ser referências para objetos de outras
    classes (campo cor das classes Alien, Canhao, Tiro)
* Inicialização de campos fora do construtor
  - Executa depois de cada chamada a "new", mas antes
    do construtor, em uma inicialização como
    public Cor cor = new Cor("azul"); cada objeto vai
    receber uma instância diferente da cor azul!
* Variáveis da classe (static)
  - Compartilhada por todas as instâncias daquela classe
  - mudou em uma, mudou em todas
  - Pode ser acessado via classe: Alien.vx
  - Em uma declaração como public static Cor cor = new Cor("azul");
    todas as instâncias compartilharaão a *mesma* instância
    da cor azul.
* Classe Canhao
  - O construtor pode receber bem poucos parâmetros, devendo
    se concentrar apenas nos parâmetros que a gente quer mudar
    de objeto para objeto. Todos os canhões serão basicamente
    iguais, exceto pela posição deles no eixo x.
* Classe Tiro
  - Instâncias de Tiro "sabem" de qual canhão saíram: campo
    de tipo Canhao. Quando um tiro é criado o canhão que o criou
    deve ser passado como parâmetro para o construtor
* Juntando tudo: classe Jogo
  - dois jogadores
  - vetor de alienígenas (número de alienígenas não aumenta)
  - tiros precisam ser criados e esquecidos: vetor é incoveniente.
    Vamos usar uma classe que java já oferece para isso:
    java.util.ArrayList. Pense nela como um vetor que cresce
    e diminui automaticamente à medida que elementos são
    adicionados e removidos.
  - construtor de Jogo não tem parâmetros, já que toda instância
    de Jogo "nasce" igual às outras. O construtor é complicado
    por causa do posicionamento dos alienígenas.

4. Métodos
---------- 

Métodos definem as operações que um objeto pode fazer. São
declarados de modo parecido com funções, só que sem o atributo
"static". Dentro de um método, a variável this é uma referência
para o objeto no qual esse método foi chamado.

A sintaxe para chamar um método é uma mistura da sintaxe de
se acessar um campo com a sintaxe de chamar uma função. O objeto
que está sendo usado para chamar o método vira o this do método,
e os argumentos da chamada são os parâmetros do método.

### 4.1. Anatomia de uma declaração de método

Vejam o método "mover" da classe Canhao:

1:    public void mover(int direcao, double dt) {
2:        this.x = this.x + direcao * vx * dt;
3:        if(this.x + tamanho > Jogo.LARGURA)
4:            this.x = Jogo.LARGURA - tamanho;
5:        if(this.x < 0)
6:            this.x = 0;
7:    }

O método começa com a declaração de sua *assinatura*:

1:    public void mover(int direcao, double dt) {
             ^^^^ ^^^^^ ^^^^^^^^^^^  ^^^^^^^^^
             tipo nome   param. 1     param. 2
             
A assinatura contém o tipo de retorno, o nome método, e
sua lista de parâmetros, onde cada parâmetro tem um tipo
e um nome. O qualificador "public" é também necessário,
e seu significado será discutido depois. A linha termina
com {, que abre o *corpo* do método.

As cinco linhas linhas seguintes são o corpo do método,
contendo o código executado quando esse método é
chamado:

2:        this.x = this.x + direcao * vx * dt;
3:        if(this.x + tamanho > Jogo.LARGURA)
4:            this.x = Jogo.LARGURA - tamanho;
5:        if(this.x < 0)
6:            this.x = 0;

Dentro do corpo, os parâmetros são *variáveis locais*.
Além deles, existe também uma variável especial chamada
*this*, que é uma referência para o objeto no qual o
método foi chamado. O corpo desse método está usando
this para acessar campos de um objeto Canhao.

O uso de this não é obrigatório; qualquer nome de variável
que não seja um parâmetro ou variável local é procurado
em this. A linha 2 poderia ser reescrita como:

2:        x = x + direcao * vx * dt;

E seu efeito seria o mesmo. Notem que no corpo original
do método *vx* já estava sendo acessado via this implicitamente.

A última linha do método simplesmente fecha o seu corpo,
terminando a declaração.

Um método pode ser chamado usando uma mistura da sintaxe de
chamar um campo com a sintaxe de chamar uma função. Se *canhao*
é uma referência para um objeto da classe *Canhao*, o método
"mover" pode ser chamado nesse objeto usando a seguinte
expressão:

canhao.mover(-1, 0.03)

Essa expressão faz o método ser executado com this apontando
para o objeto referenciado por canhao, direcao igual a -1, e
dt igual a 0.03. O resultado é fazer o campo *x* de canhao
ser diminuído de vx * 0.03, ou 6 se assumirmos que o valor
de vx é 200.

### 4.2. Quando usar métodos

Quando criar um método? Em geral, toda manipulação do estado
interno de um objeto (seus campos) deve ser feita por ele
próprio, e não por outro objeto. No exemplo acima, o movimento
de um objeto Alien manipula diversos campos da classe Alien,
e por isso é *fatorado* em um método "mover". Os outros métodos
da classe definem todas as operações que um objeto Alien
precisa fazer durante o decorrer do jogo: se desenhar ("desenhar"),
morrer ("morrer"), verificar se colidiu com um tiro ("colidiu"),
e verificar se chegou à parte de baixo da tela do jogo ("pousou").

### 4.3. Funções, ou métodos static

Um método que só manipula campos *static* de uma classe não
precisa ser um método; pode ser uma função. Basta também ser
declarado como *static*. Esse é o caso da função "inverter"
da classe Alien, que inverte a direção do movimento dos
alienígenas. Uma função pode ser chamada como um método:

  Alien a1 = new Alien(10, 50, new Cor("branco"));
  a1.inverter();

Mas é mais comumente chamada usando a própria classe, como
ao final do método "tique" da classe Jogo, que tem a expressão
"Alien.inverter()".

5. Controle de Visibilidade
---------------------------

Na seção 4.2 vimos que um objeto não deve manipular os campos
de outro objeto diretamente, mas sim chamar um método no
outro objeto para fazer isso. Essa separação não está sendo
forçada pela linguagem Java até agora; poderíamos fazer todo
o processamento feito pelo método "mover" da classe Alien
ser feito diretamente dentro do método "tique" da classe Jogo,
por exemplo.

Java não está impondo a separação entre objetos de diferentes
classes pois estamos declarando todos os campos como "public".
Essa palavra chave define a *visibilidade* do campo ou do
método. Um campo public pode ser visto, e por consequência
manipulado, por qualquer objeto, contanto que ele tenha uma
referência para o objeto "dono" do campo.

Ao invés de "public" poderíamos ter declarado os campos como
"private". Um campo "private" só é visível, e portanto
passível de ser manipulado, por métodos da classe onde está
definido. Assim, se declararmos o campo "x" da classe Alien
como private, e tivermos uma referência "a1" para um objeto
da classe Alien, só conseguiremos acessar o campo "x" de "a1"
dentro de um método da classe Alien. Isso força a separação
que vimos na seção 4.2.

Todos os campos que podem ser declarados como "private"
já estão declarados como tal nas classes Alien, Tiro, Canhao
e Jogo. Alguns campos ainda permaneceram públicos, mais
tarde veremos como rearquitetar o jogo de modo a que eles
também possam se tornar privativos.

6. Interfaces
-------------

Podemos querer modelar coisas em nossos programas que são
abstratas demais para serem representadas com classes.
Todos os objetos de uma classe possuem os mesmos campos, e
isso os torna muito parecidos entre si. Vejamos um exemplo
(o código está no projeto Funcoes). Queremos modelar
funções reais de uma variável, como as funções abaixo:

f(x) = 5x^2 + 2x
g(x) = 2^x
h(x) = ln(x)

Não podemos modelar todas essas funcões usando uma classe
"Funcao", pois cada uma dessas funções precisaria ser modelada
por diferentes campos: a primeira poderia ser modelada por
como uma função polinomial com coeficientes 0, 2 e 5, a segunda
como uma função exponencial com base 2, e a terceira como uma
função logarítmica de base e.

O que essas três funções, e qualquer outra função real de uma
variável, têm em comum é o fato de que dado um número real
(x) elas produzem outro número real (f(x), g(x), h(x), etc.).
Mas isso não é um campo, e sim um *método*: 
"double valor(double x)". 

Quando modelamos um conjunto de objetos através de seus
campos e as implementações de seus métodos não conseguimos
descrever conjuntos mais abstratos, mas se usarmos apenas
as *assinaturas* dos métodos ganhamos os graus de liberdade
que nos permitem modelar conjuntos mais abstratos. Assim,
funções são objetos que possuem um método "double valor(double x)",
não importa como ele é implementado.

A ferramenta que usamos em Java para modelar esses conjuntos
são as *interfaces*. Uma interface possui apenas *assinaturas*
de métodos (seus nomes e parâmetros), não podendo possuir
nem campos nem implementações dos métodos. Assim, nossas
funções reais de uma variável podem ser modeladas como a
seguinte interface "Funcao":

public interface Funcao {
  double valor(double x);
}

Não é necessário qualificar os métodos de uma interface como
"public", pois todos eles são públicos automaticamente. Uma
interface não pode ter o mesmo nome que outra interface ou
outra classe, mas ela pode ter métodos com o mesmo nome,
contanto que eles tenham assinaturas diferentes.

Não podemos instanciar uma interface; ela não tem campos, ou
construtores. Para ter objetos de uma interface precisamos
definir classes que *implementam* a interface. Essas classes
irão modelar subconjuntos mais concretos do conjunto abstrato
que estamos modelando com a interface. Para a interface Funcao
podemos modelar tipos específicos de função com classes:
funções polinomiais, exponenciais, logarítmicas... na
declaração da classe listamos as interfaces que ela implementa
usando a palavra-chave "implements":

public class Polinomial implements Funcao {
  ...
}

Como a classe vai implementar a interface fica a critério
dela. Ela apenas precisa declarar e fornecer implementações
para cada método da interface:

// Funções constantes
class Constante implements Funcao {
  public double c;
  public Constante(double c) { this.c = c; }
  
  // Implementação da interface
  public double valor(double x) {
      return c;
  }
}

Uma vez que temos classes que implementam uma interface
podemos criar instâncias da interface:

Funcao f = new Constante(10);
System.out.println(f.valor(2));  // imprime 10
f = new Polinomial(0, 2, 5);
System.out.println(f.valor(2));  // imprime 24

Uma variável com tipo de uma interface pode fazer referência
para objetos de *qualquer* classe que implementa a interface.
A única coisa que podemos fazer com uma variável dessas é
chamar os métodos da interface. Quaisquer campos ou outros
métodos daquele objeto ficam invisíveis, mesmo que sejam
públicos:

Funcao f = new Constante(10);
System.out.println(f.c);  // erro de compilação!

7. Herança de Classes
---------------------

Como construir variações e/ou especializações de uma
classe sem copiar/colar o seu código fonte?

Ex. Composicao -> ComposicaoVidas

Palavra chave "extends"

Palavra chave "abstract"

Subclasse e superclasse -> Subclasse extends Superclasse

Cada classe só pode ter *uma* superclasse











