BlitzMax/Lições/Orientação a objeto

Durante as edições anteriores da plataforma Blitz, sempre foi usado a programação de forma imperativa, no BlitzMax porém, foi introduzido o conceito de programação orientada a objeto. Primeiramente vamos entender como funciona este novo estilo de programação para depois colocá-la em prática.

Entendendo a POO

editar

Para entender a programação orientada a objeto vamos primeiro ver a diferença entre os dois paradigmas da programação. A orientação a objeto é uma forma que mais se aproxima do raciocínio humano, a imperativa se aproxima mais do raciocínio da máquina, por isso que se diz que a POO é um paradigma de programação de nível maior que a programação imperativa. Para entender melhor, vamos usar dois conceitos: objeto e ação.

  • Programação imperativa - Primeiro pensa na ação e depois associa aos objetos, por ex: pense na ação "andar", você pode associar vários objetos que andam como pessoas, animais, carros, etc...
  • Programação orientada a objeto - Primeiro pensa no objeto e depois associa as ações, por ex: pense no objeto "pessoa”, você pode associar várias ações que uma pessoa pode fazer, andar, correr, falar, etc...

Na programação imperativa as ações são tidas como funções, e os objetos são os tipos de dados. Na programação orientada a objetos os objetos são os tipos de dados e as ações são os métodos.

Um jogo orientado a objeto

editar

Podemos fazer um conceito do que seria um jogo orientam a objeto, nele temos os vários itens e subitens para os objetos criando hierarquias de objetos, vejamos um simples exemplo:

  • Jogo
    • Menu
      • Áudio
        • Volume
        • Mono/Stereo
      • Vídeo
        • Resolução
        • Efeitos
    • Gameplay
      • Eventos
        • Interativos
        • Não interativos
      • Inteligência artificial
        • Estados
        • Ações

Criando um tipo

editar

Primeiramente para usarmos a orientação a objeto iremos programar todo o código através de tipos de dado, sempre fazendo referência uns aos outros. Vamos começar criando um Type. E colocando atributos nele.

Type TMeuTipo
    Field x%
    Field y%
EndType

Criando um objeto

editar

Criamos o protótipo de um tipo de dado, agora iremos criar o dado (objeto) em si, para isso vamos utilizar o comando New.

Type TMeuTipo
    Field x%
    Field y%
EndType

novoObjeto:TMeuTipo = New TMeuTipo

Dando atributos a um objeto

editar

Criamos o protótipo e inicializamos o objeto, agora vamos inicializar atributos a esse objeto, para isso usaremos o nome do objeto, logo após o ponto e depois o nome do campo.

Type TMeuTipo
    Field x%
    Field y%
EndType

novoObjeto:TMeuTipo = New TMeuTipo
novoObjeto.x% = 1
novoObjeto.y% = 2

Métodos

editar

Uma das grandes vantagens da POO é a possibilidade de se usar métodos dentro dos tipos. Métodos trabalham como funções normais, mas a diferença é que na POO eles podem ser acessíveis ou não por algumas partes do programa. Para criarmos o protótipo de um método utilizamos o comando Method, para iniciá-lo fazemos da mesma forma que os Fields.

Type TMeuTipo
    Field x%
    Field y%
    Method meuMetodo()
        Print("Ola!")
    EndMethod
EndType

novoObjeto:TMeuTipo = New TMeuTipo
novoObjeto.x% = 1
novoObjeto.y% = 2
novoObjeto.meuMetodo()

Os métodos também podem alterar os valores dos campos do objeto.

Type TMeuTipo
    Field x% = 1
    Field y% = 2
    Method meuMetodo()
        x% = 10
        y% = 20
    EndMethod
EndType

novoObjeto:TMeuTipo = New TMeuTipo
Print(novoObjeto.x%)
Print(novoObjeto.y%)
novoObjeto.meuMetodo()
Print(novoObjeto.x%)
Print(novoObjeto.y%)

Vejam que no exemplo anterior alteramos os campos do objeto após chamarmos o método de alteração.

Herança

editar

Na POO herança é a habilidade que um tipo tem de herdar os atributos de outro tipo, aqui vamos definir o conceito de supertipo e subtipo que funcionarão como uma união de conjuntos em matemática. O supertipo (ou tipo pai) é o tipo que contem os campos primitivos, já o subtipo é aquele que tem contém tanto os campos da superclasse como os seus próprios campos.

Para começar vamos criar o supertipo (ou tipo pai), e inicializar um simples campo inteiro nele.

Type TSuperTipo
    Field superCampo% = 1
EndType

Agora vamos criar o subtipo, para isso vamos criar um Type e colocar o comando Extends que indica que o subtipo irá estender o supertipo, vamos também inicializar um simples campo.

Type TSuperTipo
    Field superCampo% = 1
EndType

Type TSubTipo Extends TSuperTipo
    Field subCampo% = 2
EndType

Agora vamos criar uma nova variável do tipo TSubTipo.

Type TSuperTipo
    Field superCampo% = 1
EndType

Type TSubTipo Extends TSuperTipo
    Field subCampo% = 2
EndType

variavelSubTipo:TSubTipo = New TSubTipo

Agora primeiramente vamos mostrar no console o parâmetro do próprio subtipo.

Type TSuperTipo
    Field superCampo% = 1
EndType

Type TSubTipo Extends TSuperTipo
    Field subCampo% = 2
EndType

variavelSubTipo:TSubTipo = New TSubTipo
Print variavelSubTipo.subCampo%

Para acessar o campo do subtipo fazemos normalmente com o campo nato, agora vamos acessar o campo do TSuperTipo com a nossa variável sub-tipo, isso se faz da mesma forma que o campo do super-tipo pertencesse ao sub-tipo.

Type TSuperTipo
    Field superCampo% = 1
EndType

Type TSubTipo Extends TSuperTipo
    Field subCampo% = 2
EndType

variavelSubTipo:TSubTipo = New TSubTipo
Print variavelSubTipo.subCampo%
Print variavelSubTipo.superCampo%

Agora para efeito de teste, vamos criar uma variável do supertipo e tentar acessar o campo do subtipo.

Type TSuperTipo
    Field superCampo% = 1
EndType

Type TSubTipo Extends TSuperTipo
    Field subCampo% = 2
EndType

variavelSuperTipo:TSuperTipo = New TSuperTipo
Print variavelSuperTipo.subCampo%

Você provavelmente deve ter recebido uma mensagem de erro, porque não é possível acessar um subtipo através de um supertipo.

Agora vamos testar fazendo os campos do supertipo e subtipo terem o mesmo nome.

Type TSuperTipo
    Field campo% = 1
EndType

Type TSubTipo Extends TSuperTipo
    Field campo% = 2
EndType

variavelSubTipo:TSubTipo = New TSubTipo
Print variavelSubTipo.campo%

Na execução vimos que o conteúdo exibido foi o do subtipo, isso porque o tipo tem como prioridade seus próprios campos.