Pesquisar este blog

domingo, 5 de junho de 2016

Paradigma Orientado a Objetos - suas principais características.



          Se você é um programador, ou já estudou algo sobre programação, deve ter ouvido falar de Orientação de Objetos  (OO), que nada mais é que o paradigma mais utilizado no mundo na criação de softwares. Isto ocorre devido ao tipo de abstração que este paradigma emprega aos problemas da vida real. Neste artigo vou explicar como ele funciona e as principais características e funcionalidades que o definem.

Conceituação

          Orientação a Objetos usa a comparação em que o código fonte é escrito de uma forma em que as suas funcionalidades  são agrupadas em "blocos" abstratos que se comunicam entre si, como um verdadeiro brinquedo LEGO, que são os bloquinhos que possuem encaixes e que podem ser encaixados em diversos outros bloquinhos. Esta comparação não é exagerada quanto a o OO pois uma das suas finalidades é justamente promover a reutilização de código e a fácil adaptação a novas funcionalidades.
          Estes "blocos" que cito no paragrafo anterior são pedaços de código-fonte que agrupam funções e variáveis que juntas representam um objeto da vida real, que são conhecidos por objetos (ta ai o nome Orientado a Objetos), qualquer ser da vida real pode ser transformado em um objeto. 
          Aqui está um exemplo bem intuitivo: Um carro é um meio de transporte que é formado pela união de várias peças e sistemas, todos trabalham em uma sinergia perfeita para que ele possa se mover nas pista. Se uma peça como disco de freio quebrar, nós podemos imediatamente trocar a peça defeituosa por outra peça igual a antiga sem comprometer o funcionamento do resto do carro. Bem assim deve se comportar os códigos fontes dos programas que usam o OO, o carro que simboliza um programa possuí vários "blocos" de código que  se comunicam entre si e trocam informações que no nosso exemplo são as peças do carro.
         Mas cabe ressaltar que o Paradigma Orientado a Objetos não substitui os outros paradigmas, pois ele faz uso de estruturas de outros paradigmas, ele nada mais é que uma melhoria de paradigmas mais antigos. 

O padrão OO veio para incrementar as seguintes caracteristicas:
- Definição de objetos abstratos;
- Encapsulamento;
- Herança;
- Polimorfismo;

Vou falar sobre cada uma delas nos próximos parágrafos.


Definição de objetos abstratos

           Como já foi dito e parágrafos anteriores, o OO permite abstrair objetos reais para objetos de computador. São geralmente definidos por classes que reproduzem o comportamento dos objetos reais, através de uma identidade, propriedades e métodos. 
           As classes são também ditas tipos de dados abstratos, que na verdade está definindo um tipo de objeto, por exemplo, se eu criar uma classe Casa com propriedades como : cor, tamanho, forma. Com certeza que existirão muitas casas de diferentes cores, tamanhos, formas, mas o seu tipo ainda é o mesmo que é Casa. A classe é como uma receita e o objeto é o seu resultado. Toda classe deve ser única e a partir dela podemos criar infinitos objetos. 
           Quando queremos nos referenciar ao tipo do objeto e as propriedades e métodos comuns, nós falamos sobre a classe daquele objeto. Já quando estamos manipulando um objeto já criado e armazenado na memória do computador então nós nos referimos à instância daquela classe.
           Cada objeto deve ter um identificação única para que não ocorra conflitos caso precisemos mudar alguma característica de algum objeto específico. Essa identidade dos objetos são definidas pelo compilador, ou pelo próprio programador que pode criar á mão sua identificação, atribuindo um código numérico ou alfa-numérico em uma propriedade como Id. 
           Propriedades são atributos que definem um objeto. A classe define as propriedades que serão comuns aos objetos e cada objeto define os valores destas propriedades. Exemplo: uma classe Cachorro pode ter propriedades como Nome, Raça, Cor, e os objetos podem definir seu próprio Nome, Raça e Cor como "Toby", "Pastor Alemão", "Marrom".
           Métodos são ações que os objetos podem fazer. Retomando a classe Cachorro , alguns exemplos de métodos podem ser Latir , Correr, Comer... etc.
           
         

Encapsulamento

            Através desta característica é que podemos transformar tarefas muito grandes e complexas em tarefas menores e mais simples. Podemos criar objetos, utilizar suas propriedades e métodos dentro de outros objetos. Isto nos possibilita dividir um grande problema em partes pequenas para serem resolvidas, depois de solucionadas reunimos os resultados. 
             Um exemplo prático é o pedal acelerador do carro, o usuário somente tem que empurrar o pedal para frente para que possa acelerar o motor do carro, no entanto dentro de todo o sistema do carro ocorrem coisas mais complexas até que o carro possa acelerar a rotação das rodas.O motorista não precisa saber os processos que o carro passa até acelerar o carro, basta apenas saber que ao empurrar o pedal o carro se moverá. 
             Bem assim é um código encapsulado, nós implementamos a solução dentro de um método dentro de um objeto que apenas precise que o usuário forneça alguns dados de entrada e depois ele fará a manipulação destes dados de uma forma que não precisamos ver, nem ter o conhecimento de como ele o faz, somente precisamos ver o resultado.


Herança

            É a forma pela qual criamos novas classes reaproveitando classes antigas sempre mantendo a compatibilidade entre as classes antigas e novas, ou seja, se quisermos inserir propriedades ou métodos novos em uma classe já existente, sem que estas modificações atrapalhem o bom funcionamento do programa, nós então criamos uma nova classe que somente tem as novas propriedades e então inserimos alguma notação que mostre ao compilador que queremos fazer uma herança entre classes (no java e no c# é chamado de extends) e logo depois o nome da classe que será herdada. A partir de agora a nova classe será usada ao invés da antiga e mesmo que já existam partes do código usando objetos desta classe antiga, eles não terão problemas pois os seus métodos e propriedades ainda existem.
           A herança em OO cria uma espécie de "árvore genealógica" onde a classe que está no topo foi a primeira a ser criada, a ela damos o nome de classe Pai e as suas descendentes (as classes que herdam as usas propriedades) damos o nome de classes filhas. A cada nova herança criada a repete-se esta hierarquia: a classe que será herdada é a pai e a classe que herda é a filha. É importante ter isto em mente pois todas estas são definições relativas á posição da classe nesta árvore, hora um determinado filho pode ser pai de outra classe ou um pai ser filho de uma classe superior na hierarquia.  Saber isto nos permite identificar quais métodos e propriedades podemos obter ao instanciar um objeto de uma determinada classe, pois, Uma classe pai não possui os novos métodos de  uma classe filha, mas a classe filha possui todos os métodos da classe pai. Sem falar que uma classe filha pode sobrescrever métodos da classe pai  (sem mudar a nomenclatura do método) para que ela se comporte de um modo específico. E para que a classe filha adicione um comportamento extra a implementação feita na sua classe pai, basta ela fornecer dentro do método requerido um identificador para que o compilador chame a implementação da classe pai (no java é .super) e logo abaixo adicionar o código extra.
          Herança abre um leque enorme de usabilidade de código e de abstração de problemas, sem falar que diminui a quantidade de código de um programa e é através dela que conhecemos a próxima característica principal da Orientação a Objetos que é o Polimorfismo.


Polimorfismo

       No tópico anterior nós vivos os conceitos de herança, que cria uma certa "árvore genealógica", e que as classes que estão mais abaixo nesta árvore tem acesso a todas as propriedades e métodos das classes superiores. O polimorfismo se aproveita da herança quanto a árvore que é criada pela mesma e ele acontece durante a instanciação de objetos desta árvore.
        Suponhamos que exista uma classe  chamada Telefone  e  uma classe chamada Smartfone , que representam respectivamente um aparelho telefone e um aparelho telefone celular portátil. No nosso exemplo hipotético a classe Smartfone herda de Telefone a seguinte propriedade : número, e também o seguinte método: verNumero. Já Smartfone , além de possuir as propriedades e métodos herdados, possui alguns métodos a mais.
        Agora precisamos criar uma nova classe que deve herdar de Telefone , a classe  SmartTv que , no nosso exemplo hipotético, também fará ligações e esta também possui o método chamado verNumero.
       Eis aqui o problema: durante a execução do programa o usuário é quem vai escolher qual das duas tecnologias que vai utilizar para fazer uma ligação, e isto nós não temos como saber qual o usuário vai escolher, e a depender do que ele escolher será chamado o método  verNumero, mas como saber qual dos dos dois métodos executar?
        É ai que entra o polimorfismo, para solucionar este problema nós podemos criar uma variável que possui o tipo da classe pai  e depois que o usurário escolher o dispositivo, será criado um objeto de acordo com o dispositivo escolhido. O através do polimorfismo é que nós podemos atribuir uma instância de uma classe diferente do tipo da variável,(por isto o nome polimorfismo, poli = muitas, morphos = formas), a variável poderá assumir duas instâncias: ou ela receberá um objeto do tipo Smartfone ou do tipo SmartTv .
Mas isto só é possível por que estas classes possuem um pai em comum que é Telefone ,ou seja, a classe pai suporta instancias de objetos das usas classe filhas mas as classes filhas não. Logo, quando chamar o método verNumero, não será executado a implementação do pai mesmo que o tipo da variável seja da classe pai, mas o objeto que ela armazena é de outra classe ,então , o método a ser executado será a do objeto que a variável estiver guardando. 
        Desta forma nós deixamos o computador decidir por si só o que deve ser feito com as habilidades nativas da Orientação a Objeto.


Conclusão

        Não é atoa que o Paradigma Orientado a Objetos seja tão utilizado, as possibilidades de abstrações que podem ser feitas são infinitas, podemos representar quase tudo (se não tudo!) do nosso munto para o mundo virtual. Como vocês podem notar OO não é uma bomba de conceitos, na verdade ele depende de conceitos de paradigmas mais antigos e só veio para melhorar a vida dos estudantes e programadores.


Referências

Carlo Ghezzi, Mehdi Jazayeri Programming Language Concepts , 3 edição ,USA, 1997, John Wiley & Sons,Inc. All rights reserved. Pg. 285 ,"Object-oriented languages".

segunda-feira, 28 de março de 2016

Paradigmas de programação





   Os paradigmas de programação são formas de abstrair um problema para depois implementar uma solução em alguma linguagem de programação. Eles definem como o programador deve interpretar um certo problema do mundo real ou como deve interpretar um software que fora criado por outra pessoa que usou este mesmo paradigma como base.

   Segundo Ascencio e Campos (1995 - 2010) no seu livro Fundamentos da programação de computadores,  " um paradigma de programação está intimamente relacionado à forma de pensar do programador e como ele busca a solução para os problemas. É o paradigma que permite ou proíbe a utilização de algumas técnicas de programação. Ele é capaz de mostrar como o programador analisou e abstraiu o problema a resolver ".

Aqui estão os paradigmas mais conhecidos:

- Paradigma Estruturado (Imperativo);
- Paradigma Funcional;
- Paradigma Orientado a Objetos;
- Paradigma Orientado a Eventos;

Paradigma Estruturado

Segue a concepção de executar as instruções do computador um depois do outro. Também divide o problema em partes menores que podem ser reutilizadas em outros momentos do código, também conhecido como modularização. Exemplos de  linguagens que melhor representam este conceito são Pascal, C, Cobol, Fortran.


Paradigma Funcional

Subdivide o problema em várias funções que serão utilizadas para compor o resultado. Usam expressamente o conceito de função matemática, que recebe um dado como entrada e retorna uma saída. Exemplos de linguagens: Haskel, F#, APL...

Paradigma Orientado a Objetos

Divide um problema em partes menores que interagem entre si, estas partes menores são chamadas por este paradigma de objeto. Um objeto é composto por código de uma linguagem de programação que pode ser reutilizado, pode ser criado cópias deste objeto, pode deixar de existir sem que prejudique os resto do programa, ou seja, é tratado como uma peça que tem um propósito dentro de um sistema. Exemplos de linguagens: Java,C++, C#, Python...

Paradigma Orientado a Eventos

  O programa deve se adaptar as ações do mundo exterior. A depender dos estímulos que o problema fornecer, o programa deverá corresponder da forma correta. Funciona na lei da ação e reação, um clique na tela que um usuário faz, pode ser considerado como uma ação e a reação pode ser abrir uma janela ou redirecionar o usuário para outra tela.
Exemplos de linguagens: VB, Javascript...


  As linguagens de programação utilizam pelo menos um paradigma para a construção de softwares. Dizer que uma linguagem de programação usa um paradigma não quer dizer que esta linguagem só poderá usar um paradigma. Na verdade o que ocorre hoje é o uso de algumas definições de outros paradigmas, pois desta forma, as linguagens de programação conseguem abranger um maior volume de soluções possíveis para os problemas do nosso mundo.

quarta-feira, 2 de março de 2016

Variáveis - JAVA -

Olhar geral

    Vamos discutir sobre um dos componentes principais de todas as linguagens de programação, que são as variáveis. Veremos as suas regras de nomenclatura adotadas pelos desenvolvedores em Java como padrão e código, suas classificações quanto aos usos e ciclo de vida no programa, bem como compreender como o computador entende quando esta estrutura é executada.

Conceitos

Em java as variáveis são classificadas em variáveis de instância, variáveis de classe, variáveis locais e parâmetros.

- Variáveis de instância: são variáveis que são definidas fora de métodos (métodos serão abordados no post sobre funções e procidures) e que são visíveis em todo o código da classe (Veja o post sobre Classes que será publicado em breve). Cada instância de uma classe possui uma cópia das  variáveis de instância, mas não é possível que uma classe enxergue as variáveis de outras classes.

- Variáveis de classe: são variáveis que contém em sua declaração a palavra static, ela é compartilhada por todas as instancias daquela classe, ou seja, o valor armazenado é visível à todas as classes instanciadas.

-Variáveis locais: a nomenclatura é idêntica a das variáveis de instancia, a única diferença é que estas variáveis são instanciadas dentro de métodos e construtores (construtores serão abordados mais tarde no post de Classes). Estas variáveis são somente visíveis dentro dos métodos em que foram declarados, elas são excluídas ao fim da execução do método (leia mais sobre escorpos de variáveis).

- Parâmetros: são variáveis que são declaradas junto com a assinatura do método (leia o post sobre funções e procidures). Elas são instanciadas com valores que são passados quando o método é chamado. O seu ciclo de vida é igual a das variáveis locais, apesar dos parâmetros serem instanciados fora do escorpo do método.

Léxico

    
     Java é case-sensitive, ou seja, ele diferencias os nomes de variáveis pelas letras maiúsculas e minúsculas: "Carro" e "carro" são dois nomes diferentes para o java.
     Os nomes de variáveis podem ser iniciados com uma letra Unicode, "$" ou um underscore ("_") e seguir com uma sequencia de dígitos, letras , "$" e undescores.
     Como padrão, é aconselhável que as variáveis sejam nomeadas com palavras que sejam auto-explicativas quanto a função que ela desempenhará durante o seu ciclo de vida.
     Se o nome da variável for só uma palavra, esta deve ser escrita  em letras minúsculas. Já se o nome for formado por mais de uma palavra, a partir da segunda palavra inicia-se  com uma letra maiúscula e as outras devem ser minúsculas.

                   Ex:   int idade = 19;
                           double  mesadaAnual = 1200.00;

     Não é aconselhável usar undescores para separar o nome das variáveis como em "casa_aluguel", pois esse isto caiu em desuso. É conveniente utilizar o underscore para separar nomes compostos de variáveis constantes, (será abordado o termo variáveis estáticas na secção Sintaxe logo abaixo) como em:

                   Ex:  public static  final int  CODIGO_ALIMENTO;
                           public static  final  String  NOME_DEPARTAMENTO;     
 
     Nomes de variáveis constantes devem ser escritas em letras maiúsculas.       
                       

Sintaxe


figura 1 - Exemplo de sintaxe completa de uma variável.


  

Semântico

     Quando estamos criando uma variável no nosso código java, estamos dizendo ao computador para criar um espaço na memória do tamanho que o tipo da variável sugere (veja  o post Tipo de variaveis - Java -).
     Na figura 1 o endereço da memória é então mapeado para o nome desta variável (que no nosso exemplo  é mensagem) para dentro de uma tabela de variáveis. Esta tabela é guardada pelo compilador até o fim do escorpo da variável. Quando digitar o nome da variável, o compilador irá buscar a posição da tabela que contém esse nome como nome da variável, logo depois de encontrada, ele obtém o valor que está vinculada a ela.
      As variáveis do java podem receber dois tipos de dados: os tipos primitivos e os por referência (veja em Tipo de variaveis - Java -).

Primitivos:  são as variáveis que recebem valores de tipos primitivos, esses valores são armazenados na posição da memória no formato binário, de tal modo que, se recuperarmos esta sequencia binária e convertermos no mesmo tipo, o valor será o mesmo.

Figura 2 - Esquema de uma variável primitiva

Referencia: variáveis que recebem um tipo de dado por referencia, ela não necessariamente guarda os dados que lhe são atribuídos, ela na verdade guarda um ponteiro que nada mais é que um endereço de memória que levará ao valor primitivo ou a um conjunto de valores primitivos ou até mesmo outros dados por referência.

Figura 3 - Esquema de uma variável por referência


     A diferenciação entre tipos de referência e tipos primitivos é muito importante para a programação em java (para muitas coisas também!), este conceito é o motivo de vários bugs na vida de vários programadores do mundo, então fique alerta!


Referências

DEITEL, Paul; DEITEL, Harvey. Java - como programar. 8. ed. São Paulo: Pearson, 2009.

ORACLE AND/OR ITS AFFILIATES. Variables. 2015. Disponível em: <https://docs.oracle.com/javase/tutorial/java/nutsandbolts/variables.html>. Acesso em: 29 fev. 2016.


segunda-feira, 22 de fevereiro de 2016

Tipos de variáveis - JAVA -

Olhar Geral:


Os tipos de variáveis mais utilizadas no java são : boolean, short, int, long, float, double, char , String.
Sem falar que existem ainda os tipos de array: short[ ], double[] [] ( Estes tipos serão abordados no post sobre arrays);

OBS: para entender a organização dos posts veja o post "Organização".


Léxico:



Figura 1 - tipos comuns


Sintaxe



Figura 2 - estrutura de declaração de uma variável em java.

Geralmente os tipos de variáveis são colocados antes dos nomes de variáreis. Mas eles também estão presentes no tipo de retorno de funções e tipos de parâmetros de funções. Mas desempenham o mesmo papel. 

Semântico:



Os tipos de variáveis no java são classificados de duas formas: tipos primitivos e tipos por referência.

Por trás dos panos, quando você vincula um tipo primitivo á uma variável você está determinando um tamanho de dados que aquela variável pode armazenar. Na tabela anterior mostra o tamanho em bits.

Por isso, podem ocorrer problemas se tentar atribuir o valor de uma variável de um tipo long para uma com o tipo int, pois o tipo long é de 64-bits e o tipo int é de 32-bits, o tipo inteiro não consegue comportar todos os dados de um long.



Já os tipos por referência são tipos de dados que recebem um endereço de memória. Este endereço pode ser uma definição de classe (Classes serão abordadas com mais detalhes no post) também conhecido em java como objeto ou uma coleção de vários tipos primitivos (arrays, Colections, Lists,etc). Na tabela acima o tipo String é um tipo por referência. Seu tamanho é variável devido ao fato dele ser um array de tipos primitivos (char), onde o seu tamanho em bits é dado por:

                                tamanho = [quantidade de caracteres] x  16

Mas não fique com medo dos tipos Strings! Por ser um tipo por referência, dentro das suas variáveis existem funções que facilitam a sua manipulação.
                 

No exemplo da imagem acima se quiser ver a quantidade de caracteres é só colocar o nome da variável em uma nova linha e logo depois um ponto  e digitar " length( );", isto é uma função que retorna um inteiro com o tamanho do texto da String. Teste!

//exibe o tamanho da string
System.out.println(mensagem.length( ));




Referencias:

DEITEL, Paul; DEITEL, Harvey. Java - como programar. 8. ed. São Paulo: Pearson, 2009.


ORACLE AND/OR ITS AFFILIATES.. Primitive Data Types. Disponível em: <https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html>. Acesso em: 15 fev. 2016.


Introdução ao Bibliocoding

Olhar geral


Este blog foi feito para servir como uma ferramenta de auxílio para os programadores, técnicos, estudantes e  a todos que se interessam pelas tecnologias de informação, disponibilizando um conteúdo de consulta rápida e objetiva de nomenclatura, estruturação e semântica de certas estruturas de programação.

 O conhecimento de vários programadores de TI envolve muitas vezes o estudo de várias linguagens de programação. Cada linguagem possui sua própria nomenclatura, estruturação, e paradigmas. E em meio a tantas linguagens de programação no mundo, como posso aprender a cada uma delas e nunca mais esquecê-la?

Ai vem a grande dica! O que precisamos é apenas aprender os fundamentos de cada paradigma, pois, as linguagens elas todas implementam estes fundamentos cada uma segundo o seu paradigma. 
Tendo isto em mente eu só preciso saber como que se "chama" a estrutura que eu desejo em uma linguagem nova. É como se você estivesse aprendendo uma linguagem estrangeira: você primeiro conhece os objetos e depois aprende como se referenciar a estes objetos da forma que aquela linguagem estrangeira o apresenta. 

O conteúdo deste blog é mais destinado à pessoas que já possui um conhecimento básico em linguagens de programação, mas não se preocupe se você é um iniciante ou sente dificuldades em aprendê-las, a melhor forma de aprender é ler e praticar o que aprendeu. A medida que for conhecendo e praticando, você nem perceberá que está programando como um expert.

Meu nome é Carlos Alberto Santos de Souza , e sou aluno do curso de Sistemas de Informação da Universidade Federal de Sergipe, quero ajudá-los e ao mesmo tempo me ajudar, e estou aqui para aprender junto com os meus amigos blogueiros. Conhecimento é poder!

Organização do conteúdo do blog


Estou usando a separação de conceitos usada no projeto de Compiladores e Interpretadores. A matéria que ensina esta disciplina lá é tão carrasca que depois dela não tem mais nenhuma (acho que os professores sentem tanta pena de quem pega ela que preferem dar um descanso a quem passa nela). Mas problemas à parte, seus princípios são altamente úteis (para quem acha que nunca iria usar aquilo na vida... sqn)!

Nesta matéria nós podemos aprender como as linguagens são criadas, organizadas e como elas funcionam por baixo dos panos. O design de uma linguagem é separada em três etapas :

- Léxico: nesta etapa nós estamos apenas se preocupando em como escrever corretamente cada palavra que será a ponte entre nossa linguagem e o computador. Aqui são criadas as palavras-chaves ou "keywords". Nesta seção eu priorizo a escrita correta das palavras-chaves de cada componente de uma linguagem de programação.

- Sintaxe: Assim como no nosso bom e odiado português (pelo menos pra mim), a sintaxe representa como cada palavra que nós escrevemos corretamente na vai ser disposta para que o conjunto delas, ou até mesmo uma, possa representar um pensamento, um desejo, um pedido, qualquer coisa que possamos usar para nos comunicarmos com alguém. Neste caso estamos nos comunicando com o computador. Como na nossa linguagem humana, uma palavra sozinha muitas vezes não consegue expressar o que sentimos, bem assim para o computador! Por isto existe a sintaxe, é nela que um conjunto de palavras-chaves formam uma estrutura que representa o comando que queremos que o computador entenda e execute!

- Semântico : (Será que alguém chegou nesta fase?)  não menos importante, agora sim nós vamos nos preocupar com o que realmente o computador faz (ou deve fazer) para que os nossos pedidos se tornem realidade (virtual só se for). Isso mesmo! mesmo que nós não tenhamos já escrito corretamente para o computador, ter dado o comando correto especificando ao máximo o que queremos com a sintaxe correta. Ainda sim podem ocorrer duplos sentidos! Redundâncias ! Ou canhões para matar mosquitos!
Nesta fase nós focamos em saber o que realmente acontece no computador quando escolhemos uma determinada estrutura ou algorítimo.


Conclusão


Minha vontade é poder abordar todas as linguagens que eu conheço mostrando o que cada uma tem em comum, para que possamos não decorar estruturas nem palavras-chaves, para isto existe uma documentação! O objetivo principal é aprender o que cada  linguagem de programação pode oferecer de bom para a resolução de nossos problemas. Lembrando que não existem linguagens ruins, o que existe é linguagens perfeitas para a resolução daquele problema.