orientação a objetos, simples exemplo

Iniciado por adalberto, Junho 04, 2015, 09:40:53 AM

tópico anterior - próximo tópico

adalberto

Orientação em objetos é um paradigma difícil de se introduzir no mundo da programação. Atualmente temos diversas linguagens que suportam esse mecanismo como o C++, Python, Ruby etc. Outras que forçam unicamente esse tipo de programação como Java, por exemplo.

Prisma como uma modificação do código original Lua, não tem a orientação a objetos nativamente, mas tem os mecanismos necessários para se chegar a ela. Para tanto foi implementada uma biblioteca com a classe primordial para criar as outras e com um método principal para derivar os objetos.

Pense em poo (programação orientada a objetos) como uma organização diferente. As funções (como imprima(), leia() tente() convstring() etc) e dados ( como: peso, altura, comprimento, gastos, saldo, preço, cliente_a , cliente_b etc) não ficam avulsas como na programação estruturada (blocos de funções e estruturas de dados).
Mas ficam empacotados em uma única variável chamada classe, da qual podemos declarar novas variáveis que automaticamente herdam as funções e dados da classe pai.

Bom chega de bla bla bla, vamos ao exemplo para facilitar:


                                               Um exemplo bem simples primeiro:




//exemplo classe simples:
//importando a lib "classe"
inclua'classe';

//note que a funcao que cria classe é inicial maiuscula "Classe()";

//criando uma classe com dados em valores padrões:
pessoa = Classe{nome = 'nao definido' , idade = 'nao definido' } ; //nova classe chamada 'pessoa'
funcao pessoa.mostre_dados( este )
     poe'---------------------------------------------------------------';
     imprima(este.nome);
     imprima(este.idade);
fim

//quando usamos dois pontos no método
//não precisamos passar explicitamente o parâmetro este
//fica subentendido:
funcao pessoa:denome( nome )
     este.nome = nome;
fim

funcao pessoa:deidade( idade )
    este.idade = idade;
fim

maria = pessoa:novo{  };
maria:mostre_dados();
maria:denome('Maria'); //agora damos um nome
maria:mostre_dados(); //mas idade está nulo ainda

//criando um novo objeto pessoa com dados
// já passados
joao = pessoa:novo{ nome = 'Joao' , idade = 28 };
joao:mostre_dados();



Veja a saída (Ubuntu 14.04):




                                                                     Um mais avançado:



//Para criarmos classes e depois objetos em Prisma precisamos incluir a biblioteca 'classe':
inclua'classe';

//criando uma nova classe chamada conta_bancaria:
conta = Classe{
nome = '' , //dado nome do usuario da conta
saldo = 0, //definindo um saldo padrão = zero

despositar = funcao( este , n ) 
     este.saldo = este.saldo + n; //somando o novo deposito ao saldo atual;
fim ;
sacar = funcao( este , n  )
   este.saldo = este.saldo - n ; //subtraindo do saldo atual
fim ;
poupanca = 0 ;  //definindo valor da poupanca

transf_para_poupanca = funcao(este , n )
       imprima('\n' , sis.data() , '\nDeposito da conta corrente para poupanca, valor: ' , n , '\n' );
     este.saldo = este.saldo - n; //tirando da conta corrente
    este.poupanca = este.poupanca + n; //colocando na poupanca
fim ;

transf_para_conta = funcao ( este , n )
   imprima('\n' , sis.data() , '\nDeposito da poupanca para conta, valor: ' , n , '\n' );
    este.poupanca = este.poupanca - n;
    este.saldo = este.saldo + n;
fim  ; //nunca se esqueça de separar por ponto e vírgula ou vírgula

mostre_nome = funcao(este) imprima('\nNome :' , este.nome, '\n') fim;
mostre_saldo = funcao( este )  imprima( 'Saldo conta corrente :' , este.saldo, '\n' ) fim ;
mostre_poupanca = funcao( este ) imprima('Poupanca :' , este.poupanca, '\n' ) fim

}


//feito a classe conta podemos fazer objetos a partir dela como o metodo novo

conta_padaria = conta:novo({nome = 'Conta padaria'});
//se preferir pode descartar os parênteses quando passar uma tabela.
conta_padaria:mostre_nome();
conta_padaria:mostre_saldo();
conta_padaria:mostre_poupanca();

//voce pode passar uma tabela redefinindo os dados:
conta_pessoal = conta:novo{nome = 'Paulo-conta' , saldo = 250.00 };
conta_pessoal:mostre_nome(); //imprime o nome
conta_pessoal:mostre_saldo(); //imprime o saldo conta corrente
conta_pessoal:mostre_poupanca(); //imprime saldo poupanca
conta_pessoal:despositar( 1000.00 ); //deposita
conta_pessoal:mostre_saldo(); //imprime saldo
conta_pessoal:transf_para_poupanca( 250.00 ); //transfere para poupanca
conta_pessoal:mostre_saldo();  //imprime saldo
conta_pessoal:mostre_poupanca(); //imprime poupanca


Note que:

*este* é uma palavra reservada que simboliza a tabela do próprio objeto passado como parâmetro 'este';
São usados dois pontos *:* para acessar um método de um objeto:   conta_pessoal:mostre_poupanca();


                                                             HERANÇA

Muitas vezes queremos construir uma nova classe, mas não do zero, seria bom pegar os dados e os métodos emprestados de uma classe já existente, isso se chama herança, pois  a nova classe recebe como base uma antiga e herda seus atributos:

Analise o seguinte código, uma modificação do anterior:



//Para criarmos classes e depois objetos em Prisma precisamos incluir a biblioteca 'classe':
inclua'classe';

//criando uma nova classe chamada conta_bancaria:
conta = Classe{
nome = '' , //dado nome do usuario da conta
saldo = 0, //definindo um saldo padrão = zero

despositar = funcao( este , n ) 
     este.saldo = este.saldo + n; //somando o novo deposito ao saldo atual;
fim ;
sacar = funcao( este , n  )
   este.saldo = este.saldo - n ; //subtraindo do saldo atual
fim ;
poupanca = 0 ;  //definindo valor da poupanca

transf_para_poupanca = funcao(este , n )
       imprima('\n' , sis.data() , '\nDeposito da conta corrente para poupanca, valor: ' , n , '\n' );
     este.saldo = este.saldo - n; //tirando da conta corrente
    este.poupanca = este.poupanca + n; //colocando na poupanca
fim ;

transf_para_conta = funcao ( este , n )
   imprima('\n' , sis.data() , '\nDeposito da poupanca para conta, valor: ' , n , '\n' );
    este.poupanca = este.poupanca - n;
    este.saldo = este.saldo + n;
fim  ; //nunca se esqueça de separar por ponto e vírgula ou vírgula

mostre_nome = funcao(este) imprima('\nNome :' , este.nome, '\n') fim;
mostre_saldo = funcao( este )  imprima( 'Saldo conta corrente :' , este.saldo, '\n' ) fim ;
mostre_poupanca = funcao( este ) imprima('Poupanca :' , este.poupanca, '\n' ) fim

}


//feito a classe conta podemos fazer objetos a partir dela como o metodo novo

conta_padaria = conta:novo({nome = 'Conta padaria'});
//se preferir pode descartar os parênteses quando passar uma tabela.
conta_padaria:mostre_nome();
conta_padaria:mostre_saldo();
conta_padaria:mostre_poupanca();

//voce pode passar uma tabela redefinindo os dados:
conta_pessoal = conta:novo{nome = 'Paulo-conta' , saldo = 250.00 };
conta_pessoal:mostre_nome(); //imprime o nome
conta_pessoal:mostre_saldo(); //imprime o saldo conta corrente
conta_pessoal:mostre_poupanca(); //imprime saldo poupanca
conta_pessoal:despositar( 1000.00 ); //deposita
conta_pessoal:mostre_saldo(); //imprime saldo
conta_pessoal:transf_para_poupanca( 250.00 ); //transfere para poupanca
conta_pessoal:mostre_saldo();  //imprime saldo
conta_pessoal:mostre_poupanca(); //imprime poupanca


//podemos criar uma outra classe a partir da classe conta, heranca
conta2 = Classe( conta ); //ao passar a classe conta como parametro
// a nova classe conta2 tera automaticamente os dados e metodos
//da classe conta; isso se chama heranca

//adicionando dados e metodos extras que nao existem em conta
//veja que a adicao foi posterior, sem usar chaves, isso não importa:
conta2.numero = 0;
conta2.emprestimo_total = 0;
conta2.emprestimo_restante_pagar = 0;
conta2.emprestimo_parcela = 0;
conta2.emprestimo_num_parcelas = 0;

conta2.mostre_extrato = funcao(este)
   imprima'-------------------------------------------------------------';
   imprima'                    extrato geral                              ';
   imprima( 'Titular da conta:' , este.nome , '\n');
   imprima('saldo conta:', este.saldo );
   imprima( 'saldo poupanca:' , este.poupanca );
   imprima( '\nEmprestimo:' );
   imprima( 'Valor total a pagar:' , este.emprestimo_total );
   imprima("Total restante a pagar:" , este.emprestimo_restante_pagar);
   imprima('Valor de cada parcela:' , este.emprestimo_parcela );
   imprima( 'Parcelas restantes:' , este.emprestimo_num_parcelas );
fim

conta2.emprestar = funcao( este , valor , parcelas )

      este.emprestimo_total = valor + valor * 0.2; //20 por cento do total
      este.emprestimo_restante_pagar = este.emprestimo_total;
      este.emprestimo_parcela = este.emprestimo_total / parcelas;
      este.emprestimo_num_parcelas = parcelas;

fim

conta2.pagar_emprestimo = funcao ( este )
       este:sacar( este.emprestimo_parcela );//esta funcao foi herdada de conta.
       este.emprestimo_restante_pagar  =  //nao tem problema ir para outra linha
       este.emprestimo_restante_pagar - este.emprestimo_parcela;
       
       este.emprestimo_num_parcelas = este.emprestimo_num_parcelas - 1;
       //diminuiu uma parcela;       
fim

//criando um novo objeto com alguns dados:
cliente10 = conta2:novo( {nome = 'Maria' , numero = 10 , saldo = 12000 } )
poe('------------------------------------------------------');
cliente10:mostre_nome();
cliente10:mostre_saldo();
cliente10:emprestar ( 1000.00 , 12 );
cliente10:mostre_extrato();
poe'\n------------------------------------------------------------------';
poe'             paga 1 parcela            ';

cliente10:transf_para_poupanca( 2000.00);
cliente10:pagar_emprestimo();
cliente10:mostre_extrato();
cliente10:pagar_emprestimo();
cliente10:pagar_emprestimo();
cliente10:pagar_emprestimo();
cliente10:pagar_emprestimo();

cliente10:mostre_extrato();




Veja a saída, em Ubuntu 14.04:





                                                                                       HERANÇA MÚLTIPLA

Herdar dados e métodos de várias classes ao mesmo tempo. Não há muita diferença do exemplo anterior, basta na hora de criar a nova classe passar quantas classes antigas precisar como parâmetro, veja:

nova_classe = Classe(  {meus_novos_atributos...} , classe_antigaA , classeAntigaB , ... );
Note que para mais de um parâmetro não podemos omitir os parênteses da função Classe;






Bom, pessoal, é isso aí, orientação a objetos não é muito fácil, mas merece dedicação, pois quando se programa assim fica bem organizado.
O exemplo acima é sem interface gráfica, mas basta adaptar e usar a criatividade com ig que o trabalho será legal.

Ok, qualquer dúvida deixe um comentário.

Visite o site:    http://linguagemprisma.net

rafael

Oi Adalberto,

Estou tentando trabalhar com classes, é bem interessante se parece muito com uma linguagem de consulta estruturada.

meu problema está em como pegar os índices da classe:

a intenção aqui seria pegar as cadeias e os valores

cliente=Classe{blablabla}

funcao cliente:mostretudo()
para indice, valores em ipares(este) inicio
imprima (indice,valores) fim
fim

adalberto

Ao usar os dois pontos, dentro da funcao estará disponivel um ponteiro para a tabela clientes na variavel reservada este. Basta vc usar a palavra este como se fosse a propria tabela.

Ex.

cliente =Classe { nome = ''; telef = ''};
//metodos
funcao cliente:def_nome(nome)
  este.nome = nome;
fim
funcao cliente:def_telefone (tel)
  este.telef = tel;
fim

funcao cliente:mostretudo()
  poe'------------------'
imprima(este.nome, este.telef);
fim


É muito bom programar neste estilo, depois de vc ter uma colecao de classes prontas programar fica bem mais fácil.

Falou.


rafael

Acho que não fui muito claro:

Quero pegar tudo que estiver dentro da classe,

Até coloquei uma tabela dentro da classe e consegui pegar os índices e valores da tabela mas da classe não vai:


inclua'classe'   //nome da lib é com letra minuscula

//classe cliente:
cliente = Classe{ nome='Sem Nome';  tel='61 00000 0000'; }

//funcao construtora
funcao cliente:construtor(nome,tel)
este.nome=nome;
este.tel=tel;
fim

//outros métodos:
funcao cliente:mostre()
imprima('Cliente:',este.nome, 'Tel:', este.tel);
fim

funcao cliente:denome(nome)
este.nome=nome;
fim
funcao cliente:defone(tel)
este.tel=tel;
fim

rafael=cliente:novo{}
rafael:construtor('Rafael','61 00000 9290')

funcao cliente:mostretudo()
se tipo(este.nome)=='tabela' entao
para i, v em ipares(este.nome)  inicio
imprima(i,v) fim
senao
imprima (este.nome) fim
fim


cliente.nome={}
cliente.nome[1]='RAFAEL'
cliente.nome[2]='ALVES'
cliente.nome[3]='LEMOS'

cliente:mostretudo()


imprima(tipo(cliente.nome))
imprima(tipo(cliente.tel))
imprima(tipo(cliente))


eu fiz o mesmo para ipares na classe mas não retorna nem cadeias, nem índices e nem valores.

adalberto

Vamos ver se eu entendi, vc quer pegar todos os membros da classe.

Os métodos ficam guardados em uma meta-tabela oculta com o nome de __index (duplo underline);

Os dados ficam normalmente nos campos, já que 'este' representa a própria tabela  então basta passar a variável 'este' para o 'pares'.

Veja o código abaixo:


inclua'classe'   //nome da lib é com letra minuscula

//classe cliente:
cliente = Classe{nome='Sem Nome',tel = 'Sem numero'}

//funcao construtora

funcao cliente:construtor(nome,tel)
este.nome=nome;
este.tel=tel;
fim


//outros métodos:
funcao cliente:mostre()
imprima('Cliente:',este.nome, 'Tel:', este.tel);
fim

funcao cliente:denome(nome)
este.nome=nome;
fim
funcao cliente:defone(tel)
este.tel=tel;
fim

rafael=cliente("Rafael",'444444444444');

funcao cliente:mostreMetodos()
para i, v em pares(este.__index)  inicio
  imprima(i .. ':' ,v)
fim
fim

funcao cliente:mostreDados()
  para i, v em pares(este)  inicio
    imprima(i .. ':' ,v)
  fim
fim

funcao cliente:mostretudo()
  poe'--------------------------------';
  este:mostreMetodos();
  poe'================================';
  este:mostreDados();
  poe'--------------------------------';
fim


rafael:mostretudo();


Falou, até mais.




rafael

Oi Adalberto não é isso veja:

inclua'classe'   //nome da lib é com letra minuscula
clienteC = Classe{nome='Sem Nome',tel = 'Sem numero'}
clienteT={'rafael','lemos'}

imprima(desempacote(clienteT)) // saída > rafael    lemos
imprima(desempacote(clienteC)) // saída > nome='Sem Nome'     tel='Sem numero'

Quero pegar o nome e tel e não 'Sem Nome' e 'Sem numero'

rafael

Boa tarde Adalberto,

Consegui fazer com json ficou do jeito que eu queria:
teste.json:

{
"Usuarios":
[{
"Nome": "Rafael Alves Lemos",
"Senha": "2d8d596a0b97569f9226a8c33ed9c6dbc8d88120",
"Usuario": "rafael",
"Grupo": "ADM"

}],

"Equipamentos":
[{
"Tipo": "Painel",
"Nome": "TMCAL5MN",
"Modelo": "Mikrotik RB921 - NetMetal",
"IP": "127.0.0.1",
"Ativo": "SIM"
}]
}



json.prisma:

local json = inclua'json'

tab, err = json.decod_arquivo('teste.json');

se nao tab entao erro(err) fim;

para i, v em pares(tab) inicio
imprima(i)
para r,f em pares (tab[i]) inicio
imprima (r)
para l, t em pares (f) inicio
imprima (l,t)
fim
fim
fim

rafael

Minha intenção é criar um Banco de Dados,

Mas já tô vendo que se o arquivo for maior que 10MB já dá um atraso.

Pra guardar poucos dados talvez seja bom porque não precisa instalar um banco de dados convencional.


adalberto

Blz, mas vc já deu uma olhada na biblioteca reg.pris? Você pode salvar tabelas com ela, creio que seja mais rápida que a json.

Para pegar as chaves no comando 'para' basta usar a primeira variável junto com o pares();

para chave, valor em pares(tab) inicio
   imprima(chave);
fim