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
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
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
- Áudio
- Gameplay
- Eventos
- Interativos
- Não interativos
- Inteligência artificial
- Estados
- Ações
- Eventos
- Menu
Criando um tipo
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
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
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
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
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.