SlideShare une entreprise Scribd logo
1  sur  50
Télécharger pour lire hors ligne
UNIVERSIDADE FEDERAL RURAL DE PERNAMBUCO (UFRPE)

  COORDENAÇÃO GERAL DE EDUCAÇÃO A DISTÂNCIA (EAD/UFRPE)




           Programação II




     Fernando Antonio Mota Trinta




                                                    Volume 1




                    Recife, 2010
Universidade Federal Rural de Pernambuco


Reitor: Prof. Valmar Corrêa de Andrade
Vice-Reitor: Prof. Reginaldo Barros
Pró-Reitor de Administração: Prof. Francisco Fernando Ramos Carvalho
Pró-Reitor de Extensão: Prof. Paulo Donizeti Siepierski
Pró-Reitor de Pesquisa e Pós-Graduação: Prof. Fernando José Freire
Pró-Reitor de Planejamento: Prof. Rinaldo Luiz Caraciolo Ferreira
Pró-Reitora de Ensino de Graduação: Profª. Maria José de Sena
Coordenação Geral de Ensino a Distância: Profª Marizete Silva Santos



Produção Gráfica e Editorial
Capa e Editoração: Allyson Vila Nova, Rafael Lira, Italo Amorim e Gláucia Fagundes
Revisão Ortográfica: Marcelo Melo
Ilustrações: Allyson Vila Nova
Coordenação de Produção: Marizete Silva Santos
Sumário

   Apresentação................................................................................................................. 4

   Conhecendo o Volume 1 ................................................................................................ 5

   Capítulo 1 – Introdução a Orientação a Objetos ............................................................. 7

       1. Introdução ...................................................................................................................7

       2. Evolução das Linguagens de Programação ..................................................................8

       3. Paradigmas de Programação .....................................................................................10

   Capítulo 2 – Orientação a Objetos: conceitos principais ............................................... 22

       1. Introdução .................................................................................................................22

       2. Abstração ...................................................................................................................23

   Capítulo 3 – A Linguagem Java ..................................................................................... 37

       1. Introdução .................................................................................................................37

       2. Características da Linguagem ....................................................................................38

       3. Máquina Virtual Java: o alcance de portabilidade .....................................................39

       4. Codificando um primeiro programa Java ...................................................................40

       5. JSDK – Java Software Development Kit ......................................................................42

       6. JCreator: Ambiente de programação de iniciantes ....................................................44

   Conheça o Autor .......................................................................................................... 50
Apresentação
        Caro(a) Cursista,
         Seja bem-vindo(a) ao curso de Programação II. Este curso é composto por 4 volumes. Neste primeiro
volume, vamos estudar a teoria e os principais conceitos relacionados ao paradigma de programação baseado
em objetos. Além de apresentar suas vantagens em relação a outros paradigmas de programação, será também
apresentada a linguagem de programação Java, a ser utilizada no curso para atividades práticas, como exemplos e
exercícios.
         O segundo volume é dedicado em sua totalidade à sintaxe Java, seu sistema de tipos, operadores lógicos,
comandos de decisão e repetição. No terceiro volume você aprenderá a utilizar os conceitos de orientação a objetos
utilizando a sintaxe apresentada no volume anterior.
        Por fim, no quarto e último volume serão abordados assuntos ainda mais avançados, como a ideia de
herança, polimorfismo e tratamento de exceções.
        Bons estudos!
                                                     Fernando Trinta
                                                     Professor Autor




4
Programação II




Conhecendo o Volume 1
         Neste primeiro volume, você irá encontrar o Módulo 1 da disciplina Programação II.
Para facilitar seus estudos, veja a organização deste primeiro módulo.

        Módulo 1 - Uma Introdução ao Paradigma Orientado a Objetos

        Carga Horária do Módulo 1: 15 h
          Objetivo do Módulo 1: Introduzir o paradigma de programação orientada a
objetos, a partir de um histórico evolutivo dos paradigmas de programação, ressaltando
seus benefícios em relação aos demais. Apresentar os principais conceitos do paradigma
orientado a objetos. Introduzir a linguagem de programação orientada a objetos Java, que
será utilizada no curso para utilização prática da teoria explanada.
        Conteúdo Programático do Módulo 1

    »   Introdução (Evolução dos paradigmas computacionais. O problema da
        complexidade. A ideia da abstração. Uma nova forma de encarar o problema:
        Objetos. Vantagens.)
    »   Conceitos Fundamentais do Paradigma OO (Objetos. Classes. Métodos. Atributos.
        Mensagens. Polimorfismo. Herança.)
    »   A linguagem de Programação Java (Histórico. Estrutura do código em Java.
        Compilação. Execução. O método main(). Escrevendo na tela. Independência de
        Plataforma/Máquina Virtual. Ambientes de programação.




                                                                                                          5
Programação II




                              Capítulo 1


                         O que vamos estudar neste capítulo?

                         Neste capítulo, vamos estudar os seguintes temas:

                     »   Introdução ao Paradigma Orientado a Objetos.
                     »   Evolução dos paradigmas computacionais.
                     »   O problema da complexidade.
                     »   A ideia da abstração.
                     »   Uma nova forma de encarar o problema: Objetos.
                     »   Vantagens e Desvantagens do Paradigma Orientado a Objetos.

                         Metas

                         Após o estudo deste capítulo, esperamos que você consiga:

                     »   Identificar as principais características do paradigma de programação orientado a
                         objetos.
                     »   Descrever as vantagens do paradigma orientado a objetos em relação aos demais
                         paradigmas.




6
Programação II




Capítulo 1 – Introdução a Orientação a
Objetos


             Vamos conversar sobre o assunto?


         Caro(a) Cursista, é indiscutível o papel que a tecnologia da informação tem hoje
na sociedade moderna. Praticamente toda a economia mundial está fortemente ligada a
sistemas computacionais que gerenciam bancos, sistemas comerciais, órgãos públicos,
dentre outros. Você alguma vez parou para pensar em como estes sistemas foram e
continuam sendo construídos?! Não?! Então é hora de você começar a refletir sobre como
se dá o processo de construção dos programas que realizam boa parte dos complexos
sistemas computacionais modernos. E para isto, nós vamos abordar neste volume um pouco
sobre o modelo de programação mais difundido atualmente, o paradigma baseado em
objetos. Vamos lá?




1. Introdução
         Nas últimas décadas, a sociedade moderna vem cada vez mais sendo influenciada
por sistemas de informação baseados em computador. Desde sistemas de comércio
eletrônico, passando por jogos de computador e chegando até complexos sistemas militares,
o mundo moderno é cada vez mais refém da tecnologia e dos sistemas de informação. Você
consegue se imaginar em um mundo hoje sem computadores? Sem Internet? É difícil de
imaginar. Este parece ser um caminho sem volta que fica ainda mais visível ao passo que nos
últimos anos têm crescido o uso de aplicações em dispositivos móveis, como celulares, uso
de novas aplicações baseadas em tecnologias inovadoras, como GPS, dentre outros.
         É inegável que as possibilidades do uso de novas tecnologias são importantes
facilitadores para a vida moderna, como no caso de você querer utilizar o seu celular para,
baseado na sua atual localização, descobrir qual a farmácia mais próxima ou o melhor
caminho para chegar a determinado lugar. Porém, do ponto de vista de quem constrói os
novos sistemas, isso tem se tornado um pesadelo, uma vez aumenta a complexidade destas
aplicações.
        Construir as aplicações atuais requer uma série de passos que ajudem a tratar
a complexidade destes sistemas. Estes passos e as pessoas que são envolvidas no
desenvolvimento de sistemas criaram uma disciplina, conhecida hoje como Engenharia
de Software. Esta disciplina ou processo de desenvolvimento concentra as atividades de
entender o que um sistema deve fazer (análise), propor uma solução computacional
(projeto) e desenvolver esta solução (implementar/codificar) (Figura 1). Esta última fase
está diretamente relacionada ao tema desta disciplina: criar aplicações a partir de uma
linguagem de programação.




                Figura 1 – Processo Resumido de Desenvolvimento de Aplicações


                                                                                                          7
Programação II



                             A ideia de codificar representa uma forma de escrever por meio de uma linguagem
                     de programação, o projeto da solução proposta nas fases anteriores da engenharia de
                     software. Informalmente, uma linguagem de programação pode ser definida como um
                     conjunto limitado de instruções (vocabulário), associado a um conjunto de regras (sintaxe)
                     que define como as instruções podem ser associadas. Ou seja, como se pode compor os
                     programas para a resolução de um determinado problema.
                             Os programas escritos em uma linguagem de programação são então traduzidos
                     para uma linguagem de máquina, que é compreendida pelo computador. O resultado desta
                     conversão são programas executáveis que realizam uma série de ações, como solicitar
                     dados, realizar cálculos específicos ou apresentar dados para usuários.
                               Ao longo dos anos, foram desenvolvidas (e continuam sendo) uma grande
                     quantidade de linguagens de programação, algumas de uso mais geral e outras concebidas
                     para áreas de aplicação específicas. Porém, apesar de suas diferenças, estas linguagens são
                     geralmente agrupadas de acordo com as características principais que indicam como um
                     programador (quem escreve o programa) enxerga a forma de organizar os programas. As
                     diferentes maneiras como uma linguagem organiza seus conceitos é chamada de paradigma
                     de programação. Dentre alguns dos mais conhecidos paradigmas de programação podem-
                     se citar: paradigma imperativo, paradigma estruturado e o paradigma orientado a objetos.
                     A tabela a seguir indica o índice de popularidade dos principais paradigmas de programação
                     existentes:


                                  Tabela 1 – Distribuição de Paradigmas segundo índice de popularidade
                                [Fonte: http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html]

                                                Paradigma             Indice de Popularidade

                                            Orientado a Objetos               54,6%

                                                Procedural                    41,5%

                                                 Funcional                     2,8%

                                                  Lógico                       1,1%

                             Neste momento, caro(a) cursista, você pode se perguntar: para que diferentes
                     paradigmas? Para responder esta questão é necessário voltar no tempo e entender como as
                     linguagens de programação evoluíram ao longo dos anos.



                     2. Evolução das Linguagens de Programação

                     2.1. A linguagem de máquina e a linguagem montadora

                              Um computador é organizado em um conjunto de circuitos eletrônicos. Desta
                     forma, seu controle é feito ainda através de uma forma bem primitiva, baseado em um
                     sistema binário para representação de dados e operações. Esta representação é chamada
                     de código binário ou linguagem de máquina, por ser compreendida e executada no
                     hardware do computador. Esta linguagem consiste de uma grande sequência de números
                     (1s e 0s), que instruem os computadores a realizar suas operações mais elementares, uma
                     de cada vez. A figura a seguir apresenta um trecho de um possível programa em linguagem
                     de máquina.




8
Programação II




                               Figura 2 – Código de Máquina



        Criar programas em código binário é impraticável. Para facilitar a construção
dos programas, uma nova linguagem de programação foi proposta, onde eram utilizadas
abreviações para representar as operações elementares. As linguagens que seguiram esta
estratégia foram chamadas linguagens montadoras ou assembly. Em Assembly, em vez
de números binários, utiliza-se palavras abreviadas, chamadas também de mnemônicos,
indicando a operação a ser realizada. Estas linguagens estavam mais próximas do
entendimento dos humanos, e através de um programa chamado montador, o código
binário era gerado e podia a ser executado nos computadores da época. Abaixo são
apresentados dois exemplos de instruções Assembly:

    »   MOV R1, R2 – A instrução MOV (abreviatura do termo em inglês MOVE) recebe
        como parâmetros, dois registradores: R1 e R2. Sua execução determina a cópia do
        conteúdo de R2 para R1 (equivalente R1:=R2, sendo R1 e R2 equivalente a duas
        variáveis);
    »   ADD R1, R2 – A instrução ADD (abreviatura de ADDITION) recebe como parâmetro,
        dois registradores como parâmetros: R1 e R2. Sua execução adiciona o conteúdo
        de R1 ao de R2 e o resultado é armazenado em R1 (equivalente à instrução Pascal
        R1:=R1+R2).
         Utilizando estes comandos, os programadores utilizaram Assembly para realizar
seus programas. Por exemplo, para somar dois inteiros, um programa em Assembly poderia
ser escrito através da rotina descrita abaixo.

 MOV AX,B ; registro AX recebe o valor de memória contida na variável B

 ADD AX,C ; AX recebe a soma de AX (valor de B) com o valor de C

 MOV A,AX ; variável A recebe valor de AX

          Dá para verificar que o mesmo ainda está bem próximo da linguagem da máquina
que do homem. Difícil de entender!? Bastante! Porém, isso na época permitiu que se
facilitasse a forma de se construir os programas de computador.


2.2. Aumentando o nível de abstração das linguagens

         O uso dos computadores foi se popularizando. Com isso, novas aplicações foram
propostas para os computadores que surgiram. Com isso, tornou-se necessário facilitar
ainda mais a forma como os programas de computadores eram escritos. Surgiram então as
chamadas linguagens de programação de alto nível, onde uma única instrução poderia ser
utilizada para realizar várias operações elementares do computador. Um programa tradutor
chamado compilador transformava o código em alto nível em linguagem de máquina.
Programas passaram a ser escritos em uma linguagem mais próxima da linguagem natural e
utilizavam notações matemáticas semelhantes ao cotidiano das pessoas. Um programa para
calcular o fatorial de um número poderia ser escrito como na figura a seguir.




                                                                                                       9
Programação II



                       int fatorial(int n)

                       {

                           if (n == 0)

                                 return 1;

                           else{

                                 fat = 1;

                                 for (int i=2:i<=n){

                                           fat = fat * i;

                                 }

                                 return fat;

                           }

                       }

                               Figura 3 – Trecho de um programa para cálculo de um fatorial escrito na linguagem C



                               Se mesmo para você esta versão em uma linguagem de alto nível ainda seja
                      incompreensível, pelo menos se percebe que são utilizados menos construções para se
                      realizar a mesma tarefa que em uma linguagem montadora. Desta forma, os programas
                      ficaram mais fáceis de serem compreendidos por nós, humanos. Isto facilitou bastante a
                      programação e, principalmente, a manutenção e correção de erros nos programas. Várias
                      foram as linguagens de alto nível propostas. Dentre algumas, pode-se citar Fortran, Pascal,
                      Basic e C. Algumas delas são bem populares ainda hoje.
                              O surgimento das linguagens de alto nível auxiliou programadores a construir
                      programas mais enxutos, mas fáceis de compreender e também de corrigir erros... Mas
                      onde está o conceito de paradigma nesta história?! Vamos lá então...



                      3. Paradigmas de Programação

                      3.1. Paradigma Imperativo

                               Como vimos anteriormente, um paradigma de programação explica como
                      elementos que compõem um programa são organizados e interagem entre si. No caso
                      das linguagens montadoras ou das linguagens de alto nível, a construção dos programas é
                      realizada através de instruções que indicam o que o computador deve realizar. A diferença
                      é que para linguagens montadoras, o programador precisava ser muito mais detalhista que
                      em uma linguagem de alto nível. Um simples comando na linguagem C era equivalente
                      a dezenas de linhas em uma linguagem de baixo nível. Porém, a ideia era a mesma: um
                      conjunto de instruções que ilustram uma estratégia de um ser humano em “COMO” resolver
                      um problema.
                              Esta forma de organizar os programas estabelece um primeiro paradigma de
                      programação conhecido: o paradigma imperativo. Programar um computador neste
                      paradigma significa “dar-lhe ordens” que são executadas sequencialmente. O paradigma
                      imperativo é profundamente influenciado pela arquitetura como os próprios computadores
                      são organizados, a arquitetura de von Neumann. Neste modelo, você deve pensar em um
                      programa como um computador que tem memória que guarda um estado por meio de


10
Programação II



dados (variáveis), e que recebe instruções que modificam e apresentam estes dados, como
ilustrado na figura a seguir:




                        Figura 4 – Modelo Imperativo de programação



        Como todas as arquiteturas de computadores existentes hoje se baseiam na
arquitetura de Von Neumann, os ambientes de execução das linguagens imperativas são
bastante eficientes.
         Porém, mesmo assim, programas escritos no paradigma imperativo ainda são
muito detalhistas, o que requer um grande esforço na construção e, principalmente,
na manutenção dos programas. Conforme a complexidade dos programas aumenta, a
legibilidade, ou seja, a facilidade com que os programas podem ser lidos e entendidos,
torna-se também mais difícil. Com isso, a manutenção continuou sendo um problema, e
erros acabavam sendo introduzidos sem querer durante o processo de depuração (correção)
de programas.


3.2. Paradigma Procedural

         Uma evolução do paradigma imperativo foi a percepção que certas sequencias de
instruções que são repetidas em vários pontos de um mesmo programa. Estes sequências de
passos poderiam ser agrupadas em procedimentos e funções (também chamados de sub-
rotinas) definidas pelo programador e serem chamadas de diversos pontos do programa,
como no caso de criarmos uma função que calcule o valor do fatorial de número (Figura 5).
Por esta característica, o paradigma imperativo também é conhecido na literatura como o
paradigma procedural.




                   Figura 5 – Paradigma Imperativo VS Paradigma Procedural




         O paradigma procedural foi durante muitos anos o padrão para linguagens de
programação. Este paradigma acabou influenciando também a forma como a própria análise
e projeto das aplicações eram realizados. O paradigma procedural induzia que sistemas
mais complexos precisavam ser “quebrados” em partes menores, mas fáceis de lidar. Este
princípio de “dividir para conquistar” é a abordagem padrão que os desenvolvedores de
sistemas utilizam para lidar com sistemas complexos.
       No caso do paradigma procedural, o sistema era dividido em muitas funções
que representavam as diversas funcionalidades que o programa tinha que fazer. Isso era

                                                                                                        11
Programação II



                      repetido até se chegar a um nível que as funções eram claras o suficiente para entender
                      seu funcionamento, ou mesmo para serem reaproveitadas em diferentes pontos de um
                      programa. Com procedimentos, funções menores eram mais fáceis de entender, além de
                      facilitar eventuais correções de um programa, em caso de erros.
                               De certa forma, esta abordagem de lidar com a complexidade também lida com um
                      conceito chave para a construção de sistemas e a programação de aplicações: a abstração.
                      A ideia de abstração faz com que os desenvolvedores concentrem seus esforços no que é
                      relevante, deixando detalhes irrelevantes para serem tratados mais tarde. Abstração dentro
                      de um paradigma de programação indica como os problemas são encarados. Os conceitos
                      utilizados para resolver estes problemas são as abstrações utilizadas por um paradigma.
                      No caso do paradigma procedural, as abstrações utilizadas para decompor um problema
                      complexo são as sub-rotinas (funções e/ou procedimentos).
                               O uso de sub-rotinas separa dados (variáveis) e operações (procedimentos) sobre
                      os dados, onde a ideia de funções e procedimentos manipulando um conjunto de dados
                      surgiu como um modelo natural para representar como as aplicações.
                              Porém, esta abordagem também apresenta seus problemas. Primeiro, o caminho de
                      execução do programa ficou mais complexo devido à chamada de funções e procedimentos
                      em diversas partes do código. A confusão de chamadas e desvios era tão grande que se
                      criou um termo específico para os programas mal-estruturados a partir de várias chamadas
                      de sub-rotinas, o “código espaguete” (Figura 6).




                                                       Figura 6 – O código espaguete
                                   [Fonte: http://www.yourdictionary.com/images/computer/SPAGETI.GIF]



                               No entanto, o maior problema está relacionado com a separação de dados e
                      procedimentos, pois várias partes de um mesmo programa podiam alterar os valores de
                      variáveis compartilhadas. Em muitos casos, a modificação de uma variável por uma sub-rotina
                      causava a falha na execução de outra sub-rotina que dependia do valor da mesma variável.


12
Programação II



Além disso, como procedimentos utilizavam valores em variáveis separadas, uma alteração
na representação de uma variável poderia exigir uma alteração em cascata em todas as sub-
rotinas que dependessem deste valor. Ou seja, um pesadelo para o programador!




            Figura 7 – Relação entre dados e procedimentos no paradigma procedural



        Vejamos isso em exemplo mais claro, como o cálculo de uma folha de pagamento
de uma empresa. Neste caso, os dados relativos a cada um dos funcionários ficariam
espalhados no programa. Seria necessário recuperar estes dados para cada funcionário
obter e então realizar o processamento do cálculo da folha de pagamento (Figura 8). Este
processamento seria representado por uma função ou uma sub-rotina.




             Figura 8 – Cálculo de uma folha de pagamento no paradigma procedural



         Com o aumento da complexidade das aplicações, o gerenciamento entre
procedimentos e dados dispersos criava um pesadelo para os programadores que precisavam
realizar manutenções no sistema. Modificações em um dado poderiam desencadear um
processo de atualização em vários procedimentos.




   Figura 9 – Dificuldade do gerenciamento de dados e procedimentos no paradigma procedural



        Além disso, verificou-se que ao longo dos anos, os procedimentos mudavam muito
mais que os dados manipulados. Como exemplo, as regras que podem ser associadas ao
cálculo do salário de um funcionário variam muito mais que os dados do funcionário,
como seu nome ou seu cargo. Desta forma, era necessária uma nova forma de organizar os
sistemas.


                                                                                                               13
Programação II



                      3.3 Programação Modular e Estruturada

                              Para tentar melhorar as deficiências do paradigma procedural, surgiu
                      então a programação modular. Nesta abordagem, o programa é dividido em vários
                      componentes ou módulos. Ao contrário do paradigma procedural, módulos combinam
                      dados e procedimentos. Um módulo é composto de dados que são manipulados pelos
                      procedimentos deste módulo. Cada módulo fornece um conjunto de procedimentos para
                      que outras partes de um programa possam acessar dados internos de um módulo. Este
                      conjunto de procedimentos ou funções é conhecido como interface do módulo. Desta
                      forma, dados internos de um módulo são protegidos contra manipulações indevidas de
                      outros módulos, em um princípio conhecido como encapsulamento.
                              Estas características trouxeram vantagens em relação aos seus predecessores.
                      Dentre algumas, pode-se citar:

                          »   Estrutura do programa fica mais clara ao agrupar funções e variáveis relacionadas
                              em um mesmo módulo;
                          »   Possibilidade de alterar módulos separadamente. Uma vez que cada módulo
                              preserve sua interface visualizada por outros módulos, modificações internas e
                              novos procedimentos podem ser incluídos;
                          »   O acesso a dados internos de um módulo é feito através de sua interface. Com
                              isso, tem-se um maior controle sobre operações indevidas sobre estes dados. Por
                              exemplo, é possível verificar se um dado pode ou não ser modificado para um
                              determinado valor, antes de se efetivar a mudança.
                              Este estilo de programação também muito referenciada como programação
                      estruturada, devido a uma melhor organização dos conceitos utilizados nos programas.
                      A programação estruturada tornou-se um sucesso e, a partir de seus conceitos, métodos
                      de modelagem e análise foram propostos para facilitar o projeto das novas aplicações que
                      surgiam na época em que surgiu a programação estruturada, como a Análise Estruturada de
                      Tom DeMarco, e a Análise Estruturada Moderna, de Edward Yourdon.
                                Com as ideias de módulos, encapsulamento e interfaces, a programação modular
                      permitiu um melhor aproveitamento e distribuição de programas. Os módulos construídos
                      por um programador poderiam ser reaproveitados por outros programadores, sem a
                      necessidade de se entregar código-fonte. Bastava que os programadores que desejassem
                      utilizar um módulo soubesse a interface deste módulo. Imagine um módulo como uma
                      biblioteca de funções. Poderia haver um módulo para fazer, por exemplo, a verificação se
                      um CPF é válido ou não. A única coisa que um programador precisaria saber é que este
                      módulo possui uma função chamada valida_cpf, que recebe como parâmetro um número
                      de 11 dígitos e retorna verdadeiro se este número representa um CPF válido. Para os
                      programadores que vão utilizar o módulo, ele é considerado uma caixa-preta, no sentido
                      que não se sabe como ele funciona internamente. O importante é que ele forneça o
                      resultado que se espera dele.
                               Porém, a programação modular também apresenta seus problemas. O primeiro
                      e principal problema é o fato que módulos não eram naturalmente extensíveis. Isso
                      significava que para fazer alterações em módulo, era necessário entrar no código-fonte e
                      diretamente realizar as modificações. E em muitas situações, se via a necessidade de criar
                      novas funcionalidades dos programas a partir de módulos já existentes.




14
Programação II



3.4. O Paradigma Orientado a Objetos

                                  O termo “programação orientada a objetos” foi criado
                          por Alan Kay (imagem ao lado), autor da linguagem Smalltalk.
                          Sua proposta visa aproximar a maneira como construímos os
                          programas de computador do mundo real.
                                   O mundo real é composto por entidades que interagem,
                          que trocam serviços entre si para realizar suas tarefas. Na
                          proposta de orientação a objetos, estas entidades são chamadas
                          objetos.


        Objetos podem representar tanto entidades concretas (como uma pessoa ou
um livro) quanto entidades abstratas (como uma transação bancária ou uma sessão de
um usuário ao acessar um site). Para identificar objetos são empregadas técnicas que os
próprios seres humanos utilizam para organizar seus pensamentos, como classificação de
elementos, diferenciação entre parte e todo, troca de mensagens, dentre outros.
        Alan Kay utilizou uma analogia com um sistema molecular, batizada então de
“analogia biológica”. Nesta proposta, ele se questionou: “como seria um sistema de
computador que se organizasse como um ser vivo?”. Sua proposta estabelecia que:

    »   O sistema seria organizado em células, onde cada célula se comportaria como uma
        unidade autônoma;
    »   Cada “célula” interagiria com outras células através do envio de mensagens para
        realizar um objetivo comum;
         Para Kay, objetos do mundo real também se comportam como estas células. A
partir de sua analogia biológica, ele estabeleceu os princípios básicos para a orientação a
objetos. São estes:

    1. Qualquer coisa é um objeto;
    2. Objetos realizam tarefas através da requisição de serviços a outros objetos;
    3. Cada objeto pertence a uma determinada classe. Uma classe agrupa objetos
       similares;
    4. A classe é um repositório para comportamento associado ao objeto;
    5. Classes são organizadas em hierarquias.

        3.4.1. Estabelecendo um exemplo

        Para melhorar sua compreensão, vamos utilizar um exemplo prático. Imagine
a situação em que um cliente chamado Ian deseja comprar uma pizza via um serviço de
entrega em domicílio. Ian interage com uma atendente (Maria) e faz sua solicitação.
Maria por sua vez interage com Mário, o pizzaiolo, repassando a solicitação de Ian, uma
vez que quem sabe fazer a pizza é Mário, afinal ele é o pizzaiolo. Após a pizza ficar pronta,
ela é entregue ao Zé, o motoboy, que tem por função entregar a pizza a Ian e receber o
pagamento. A Figura 10 ilustra a interação entre estes personagens.




                                                                                                            15
Programação II




                                       Figura 10 – Um exemplo para a orientação a objetos na vida real



                               Embora o exemplo acima ainda possa ser refinado e inserir ainda mais participantes,
                      ele é suficiente para ilustrar os conceitos propostos pelo paradigma orientado a objetos.
                      Primeiramente, cada elemento que participa do processo é considerado um objeto. Cada
                      objeto é uma entidade única no sistema. No caso temos Ian, Maria, Mário e Zé como
                      objetos. Não existem duas “Marias”. Poderiam até existir duas funcionárias com o mesmo
                      nome, mas não seriam a mesma pessoa. Cada objeto tem dados ou propriedades que os
                      identificam. No caso, cada pessoa no processo tem um nome.
                               Cada objeto interage com os demais por meio da solicitação de serviços. No caso,
                      Ian solicita seu pedido através da atendente Maria, que lhe fornece os produtos que ela
                      pode entregar a Ian. De forma semelhante, Maria solicita a Mário a pizza escolhida por Ian,
                      passando informações necessárias para realização deste serviço, como o sabor da pizza e o
                      tipo da borda, como ilustrado na Figura 11.




                              Figura 11 – Solicitação de um serviço através da troca de mensagem entre objetos



                               Seguindo sua análise, cada objeto pertence a uma determinada classe que agrupa
                      objetos similares. No nosso exemplo, a pizzaria não atende apenas ao cliente Ian. Podem
                      existir outras dezenas de clientes que também podem fazer seus pedidos à Pizzaria. Estes
                      clientes possuem características comuns, como um cadastro na loja ou um endereço de

16
Programação II


entrega. Obviamente, para cada cliente, os valores associados a estas propriedades são, em
geral, diferentes. Estes objetos são tratados e agrupados como um tipo único de objeto,
uma classe. Neste caso, poderíamos agrupar Ian, Cris e Evandro como objetos da classe
Cliente, como ilustrado na Figura 12.




                          Figura 12 – Objetos de uma mesma classe



         Por fim, classes são organizadas em hierarquias. No nosso exemplo, Maria, Mário
e Zé poderiam ser agrupados em uma classe que representem os funcionários da Pizzaria
(Figura 13). Estes possuem características comuns como um salário, um horário de trabalho.
Porém, estes também poderiam ser classificados como pessoas, com atributos como nome,
sexo, dentre outros. Neste caso, a classe Pessoa englobaria tanto funcionários quanto
clientes, indicando que existem certas propriedades comuns, como o fato de tanto clientes
quanto funcionários possuírem um nome.




                         Figura 13 – Hierarquias de classes de objetos



        Mas vistos estes conceitos, em que a orientação a objetos pode melhorar a forma
como programamos nossas aplicações? Para isso, vamos pegar o exemplo do cálculo de
uma folha de pagamento de uma empresa, como ilustrado na Figura 14.




                  Figura 14 – Uma folha de pagamento no modelo estruturado

                                                                                                         17
Programação II



                              Relembrando: como os dados e funções são separados, calcular o custo total da
                      folha requer que saibamos individualmente todos os dados de cada funcionário, o que
                      acabava por fazer com que a evolução do sistema ficasse bastante complicada. Agora veja
                      como seria uma possível versão utilizando a abordagem orientada a objetos (Figura 15).




                                         Figura 15 – Uma folha de pagamento no modelo de objetos



                               Nesta versão, cada funcionário é representado por um objeto. Um objeto atua
                      como um módulo que engloba dados, e também fornece operações que manipulam tais
                      dados. Os dados internos de cada objeto são chamados atributos, enquanto as operações
                      que um objeto fornece são chamados de métodos. No caso, todo objeto que representa
                      um funcionário possui como atributos seu nome, seu cargo, seu salário fixo e uma série
                      de outros atributos que são comuns a qualquer funcionário da empresa. Para se calcular
                      seu salário, cada funcionário oferece um método chamado calculaSalario, que internamente
                      utiliza os dados de cada objeto e fornece o valor de seu salário individual. Para calcular o
                      custo total da folha de pagamento seria então somar os valores obtidos pela chamada de
                      cada método calculaSalario, em cada objeto que representa um funcionário da empresa.
                              A orientação a objetos representa uma nova forma de enxergar e modelar o
                      mundo como um conjunto de objetos inter-relacionados, interagindo por meio da troca de
                      mensagens. A abstração escolhida (objeto) combina estrutura de dados e comportamento
                      funcional, fazendo com que os dados sejam preservados e procedimentos modificados
                      mais facilmente, sem causar impactos tão profundos quanto o paradigma estruturado. A
                      ocorrência de erros ou alterações vão estar associadas a um único módulo ou a um pequeno
                      grupo deles, onde é mais fácil depurar e isolar erros.
                               Esta forma de organizar os programas cria um modelo mais intuitivo e fácil
                      de usar, mas principalmente, aumenta a possibilidade de reuso entre objetos. Objetos
                      podem ser criados a partir de outros objetos. Por exemplo, você poderia criar um objeto
                      que representasse um funcionário diferenciado, como aquele cujo salário fosse baseado
                      em comissões, e não em um salário fixo. Este objeto poderia ser criado através de um
                      mecanismo especial de extensão chamado Herança. Resumidamente, este novo objeto
                      teria as mesmas características de um funcionário comum, mas poderia ter dados a mais,
                      assim como seus métodos poderiam ser modificados, como no caso de seu salário.


                      3.5. Programação Orientada a Objetos VS Programação
                      Estruturada

                              A forma de organizar um programa usando orientação a objetos é essencialmente
                      diferente do desenvolvimento tradicional de software. Mesmo assim, alguns conceitos do
                      modelo orientado a objetos podem ser equiparados a conceitos do modelo estruturado,


18
Programação II



como visto na figura a seguir.




               Figura 16 – Paradigma orientado a objeto VS Paradigma Estruturado



          A programação orientada a objetos é especialmente útil à medida que os sistemas
tornam-se cada vez mais complexos, e por consequência, seus programas ficam cada
vez maiores. Grandes programas se beneficiam mais com a modularidade oferecida por
objetos. Dividindo o programa em vários módulos independentes (objetos), aumenta-se a
flexibilidade e a facilidade para manutenção do programa como um todo.
         Na programação estruturada, a reusabilidade é limitada a trechos de algoritmos
representados por meio de sub-rotinas. Na programação orientada a objeto é possível
reutilizar todo um módulo, no caso o objeto, com seus métodos e seus atributos. Em geral,
a programação orientada a objetos ainda apresenta como vantagens: código mais lógico,
e melhor encapsulado, uma maior facilidade de manutenção e extensão do código, um
melhor reaproveitamento de código, dentre outros.
         Como desvantagens, pode-se afirmar que o aprendizado de uma linguagem
orientada a objetos é mais complexo, principalmente para aqueles já familiarizados com o
paradigma estruturado. É necessário mudar a forma de pensar na solução de um programa,
utilizando conceitos não tão simples quanto do paradigma estruturado. Por fim, dificilmente
uma linguagem orientada a objetos conseguirá ter um desempenho em tempo de execução
superior a linguagens não orientadas a objetos.


              Exercícios


    1. Com suas palavras conceitue: (a) linguagem de programação e (b) paradigma de
       programação.
    2. Utilizando a Internet, verifique quais são os outros paradigmas de programação
       existentes além dos apresentados neste capítulo. Explique qual o propósito de pelo
       menos dois outros paradigmas.
    3. Em sua opinião, ainda faz sentido hoje se programar em uma linguagem de baixo
       nível como Assembly?! Justifique sua resposta.
    4. Para muitos pesquisadores, o paradigma orientado a objetos é apenas uma
       extensão do paradigma estruturado. Você concorda ou discorda desta opinião?
       Justifique.
    5. Utilizando a abordagem de uma programação estruturada, resolva o seguinte
       problema. É necessário descobrir o atleta que mais marcou gols em um campeonato
       de futebol. Descreva (em português ou em linguagem de programação que você
       conheça) como seria solução deste problema.
    6. Utilizando o mesmo problema da questão anterior, como seria a solução utilizando


                                                                                                          19
Programação II



                              objetos.




                                     Minibiografia




                        Edsger Wybe Dijkstra (11 de Maio de 1930 — 6 de Agosto de 2002) foi um pesquisador holandês
                        mundialmente conhecido por suas contribuições nas áreas de desenvolvimento de algoritmos e
                        programas de linguagens de programação. Foi o precursor da ideia contrária ao uso de comandos
                        “GOTO” em linguagens de programação, um recurso muito utilizado na sua época. Em seu artigo
                        “A Case against the GO TO Statement”, Dijkstra alertou para vários erros decorrentes do uso da
                        declaração GOTO. Uma transcrição deste artigo pode ser visto na URL: http://www.cs.utexas.
                        edu/~EWD/transcriptions/EWD02xx/EWD215.html. Suas pesquisas impulsionaram o surgimento
                        da programação estruturada.Em 1972, recebeu o Prêmio Turing por suas contribuições com o
                        ALGOL e no campo de linguagens de programação.




                                   Vamos Revisar?


                               Você estudou, neste capítulo, como as linguagens de programação evoluíram ao
                      longo dos anos no intuito de facilitar a vida dos programadores das aplicações modernas.
                      Esta evolução foi motivada principalmente pela crescente complexidade dos programas.
                      Com isso, as linguagens têm focado principalmente em criar abstrações que melhorem a
                      compreensão e manutenção destes programas. Você também viu que é possível classificar
                      as linguagens em grupos que seguem o mesmo conjunto de ideias sobre a estruturação e
                      execução de um programa, os chamados paradigmas de programação. Desde o paradigma
                      imperativo até o paradigma estruturado, vários foram os avanços na estruturação dos
                      programas, como a reutilização através de sub-rotinas até o uso de módulos autocontidos
                      que protegem seus dados de acesso indevido. Apesar destas evoluções, havia muito o que
                      evoluir, principalmente no que diz respeito ao reuso dos programas. Para isso, uma nova
                      abordagem de programar foi proposta: a orientação a objetos. Neste novo paradigma,
                      programas se aproximam mais do mundo, através de objetos que interagem para a
                      realização de uma tarefa. No próximo capítulo, você verá com mais detalhes os principais
                      conceitos deste novo paradigma.




20
Programação II




         Capítulo 2


    O que vamos estudar neste capítulo?

    Neste capítulo, vamos estudar os seguintes temas:

»   Conceitos fundamentais do paradigma orientado a objetos, como:
     ›   Classes, Objetos, Atributos e Métodos.
     ›   Abstração.
     ›   Encapsulamento.
     ›   Polimorfismo.
     ›   Herança.

    Metas

    Após o estudo deste capítulo, esperamos que você consiga:

»   Descrever os principais conceitos utilizados no paradigma orientado a objetos.




                                                                                                      21
Programação II




                      Capítulo 2 – Orientação a Objetos:
                      conceitos principais


                                   Vamos conversar sobre o assunto?


                               No capítulo anterior, você viu que ao longo dos anos a programação buscou
                      uma constante evolução no intuito de facilitar a vida dos programadores. O progresso
                      na organização dos programas evoluiu. Porém, os sistemas também ficaram cada vez
                      mais complexos. Em particular, os paradigmas de programação até então falhavam
                      principalmente em relação à reutilização de código. Para enfrentar este problema, um
                      novo paradigma surgiu: a orientação a objetos. Vamos abordar neste capítulo os principais
                      conceitos relacionados a esta nova forma de organizar seus programas. Este capítulo é
                      fundamental para seu bom progresso no curso. Então, vamos aprender?




                      1. Introdução
                              Como vimos no capítulo anterior, a programação orientada a objetos surgiu
                      como uma nova abordagem para tratar a inerente complexidade dos novos sistemas. A
                      programação orientada ao objeto (object-oriented programming) pode ser considerada
                      como uma extensão quase natural da programação modular. Apesar de seus conceitos já
                      terem sido estabelecidos desde a década de 70, apenas em meados da década de 90 que
                      este paradigma começou a ganhar maior destaque na comunidade de desenvolvimento de
                      sistemas.
                               Seu uso enfatizou uma ideia que até então passava despercebida: a aproximação
                      com o mundo real. Na programação orientada a objetos temos a necessidade de buscar
                      as entidades de um domínio, onde através da qual um indivíduo observa a realidade
                      (domínio) e procura capturar sua estrutura (abstrair entidades, ações, relacionamentos)
                      com elementos que forem considerados relevantes para a descrição desse domínio. Com
                      as entidades de domínio identificadas, podemos utilizar as técnicas de abstração para
                      a composição das classes abstratas, construindo desta maneira um sistema facilmente
                      reutilizável nas suas estruturas internas.
                               A abordagem OO (orientada a objetos) enfatiza duas características: (i) reutilização
                      de código e (ii) modularidade. Nisto, OO é imbatível quando comparada com as metodologias
                      antigas. Em termos de modelo computacional podemos dizer que enquanto as metodologias
                      tradicionais utilizam o conceito de um processador, uma memória e dispositivos de I/O para
                      processar, armazenar e exibir as informações. A orientação a objetos emprega um conceito
                      mais real, mais concreto: o de Objeto.
                             Porém, além de objetos, existe uma série de outros conceitos que são
                      importantes para a compreensão do paradigma OO, representados na Figura 17. São eles:
                      encapsulamento, polimorfismo, herança, composição e abstração.




22
Programação II




                     Figura 17 – Os pilares do paradigma orientado a objetos



       Vamos dar uma olhada agora como cada um destes conceitos contribui no
paradigma OO.



2. Abstração
         Abstração é considerada a habilidade de modelar características do mundo real
do problema que o programador esteja tentando resolver. Ao mesmo tempo, para melhor
lidar com a modelagem de problemas complexos, este processo mental indica que se
deve ignorar detalhes não relevantes e focar nas características essenciais dos elementos
modelados. Com isso, uma realidade complexa pode ser representada em um modelo
simplificado, como os objetos no paradigma OO.
         A abstração na descrição de objetos depende do ponto de vista e objetivo de
quem faz a descrição. Grady Booch, um atuante e renomado pesquisador na comunidade
científica, ilustra esta observação na sua frase: “Uma abstração depende mais do observador
do que do objeto observado”. Por exemplo, a visão de um apartamento por um engenheiro
civil tende a ser diferente da de um decorador de ambientes. O primeiro deve se preocupar
mais com os aspectos relacionados ao posicionamento de vigas de sustentação, colunas,
dentre outros. Já um arquiteto se preocuparia mais em como otimizar o espaço, maximizar
a circulação de ar, do melhor local para colocar mesas e cadeiras.
         Estas diferentes visões ocorrem pelo diferente interesse que os dois profissionais
tem sobre a mesma entidade observada: o apartamento. O mesmo vale para a programação,
pois só devemos representar nos sistemas que vamos criar, aquelas características que nos
interessam dos objetos reais. Como exemplo, ao modelarmos um objeto avião no contexto
de um sistema de venda de passagens aéreas, não vai nos interessar a característica do
número de turbinas do avião, mas sim, seu número de assentos disponível.
        Existe uma série de princípios que são utilizados por nós, humanos, para realizar
abstrações em nosso cotidiano. Vamos ver como alguns destes princípios e como eles se
aplicam no paradigma OO.


2.1. Classificação/Instanciação

        Classificação é um mecanismo de abstração através do qual o ser humano percebe
a existência de um conjunto de fenômenos da realidade (elementos, interações) com
algumas características em comum e atribui um nome (conceito) a esse conjunto (classe) de
fenômenos. Já a instanciação é o processo inverso à classificação.
         Na orientação a objetos, este princípio é utilizado para a identificação de classes e
objetos. As duas ações possíveis são:

    »   Classificar significa agrupar objetos com base em estruturas e comportamentos
        semelhantes;


                                                                                                             23
Programação II



                          »   Instanciar objetos significa gerar novos exemplares a partir de uma descrição
                              abstrata de um objeto genérico.
                             Vejamos o exemplo na Figura 18, que ilustra estes processos no contexto de dois
                      estudantes, João e Maria. Ambos são indivíduos, com seus dados particulares, como seus
                      nomes. Porém, ambos podem ser agrupados no conjunto de indivíduos que representam os
                      estudantes.




                                             Figura 18 – Classificação/Instanciação de objetos



                              A “semântica” ou o significado do mecanismo de classificação equivale a um
                      mecanismo de pertinência. Neste mecanismo, o fato de um objeto pertencer a uma
                      determinada classe pode ser melhor caracterizado se ocorrer uma relação do tipo “é um / é
                      uma”. Por exemplo, “Maria é uma estudante”.
                               A partir desta abstração, pode-se então melhor entender os conceitos de objetos e
                      classes, atributos e métodos.
                               Objetos representam entidades do mundo real, quer sejam estas concretas ou
                      abstratas, sobre as quais são armazenados dados e temos operações para manipulá-los.
                      Objetos também se caracterizam por ter uma identidade única, um comportamento e um
                      estado. A identificação de objeto deve ser única, uniforme e independente do conteúdo do
                      objeto. Isso implica que podem haver objetos com características semelhantes (como dois
                      martelos azuis ou dois funcionários com o mesmo nome), mas que são distintos.
                              Uma classe é abstração das características mais importantes de um grupo de
                      objetos semelhantes. Cada classe descreve um conjunto (possivelmente infinito) de objetos
                      individuais. A partir de uma classe podem ser gerados diferentes objetos e por isso, cada
                      objeto é dito ser uma instância de uma classe. Assim, cada instância de uma classe tem seus
                      próprios valores para cada dado que o caracteriza, mas também podem compartilhar dados
                      e comportamento com as outras instâncias da classe. Implicitamente, cada objeto contém
                      uma referência para sua própria classe -- em outras palavras, ele sabe o que ele é.
                                Existe hoje uma representação bastante difundida para representar graficamente
                      classes em um modelo orientado a objetos. Esta notação é definida por uma linguagem visual
                      chamada UML (do inglês, Unified Modeling Language). UML é utilizada para representação
                      de muitas etapas durante a análise de um sistema. Ela é formada por vários diagramas.
                      Um deles é o diagrama de classes, em que classes são representadas graficamente. Para
                      facilitar nossa explicação sobre os conceitos OO, utilizaremos a notação UML para descrever
                      as classes nesta disciplina. Em UML, uma classe é representada como descrito na figura a
                      seguir.




24
Programação II




                             Figura 19 – Notação UML para Classes



         Nesta notação, há uma caixa retangular composta de três partes. A primeira parte
(localizada no topo do retângulo) define o nome da classe. Esta é única parte que deve existir
na notação UML para representar uma classe. A parte intermediária diz qual é a estrutura
da classe. Enquanto a parte inferior informa qual é o seu comportamento, através das ações
que objetos desta classe podem realizar. Para melhor exemplificar, a classe Estudante tem
como estrutura interna o nome do estudante e o curso ao qual ele está vinculado. Como
ações, é possível pedir para um objeto imprimir seu nome.
        Cada objeto possui um conjunto de características ou informações que os
caracteriza, chamadas então de atributos. O conjunto de atributos também é chamado
de estrutura da classe. Por exemplo, a classe Estudante pode conter como sua estrutura
informações como o nome, sexo, data de nascimento, colégio ou faculdade, dentre outros.
Os atributos possuem valores, funcionando como variáveis. Por exemplo, o atributo nome
para um dos objetos da Figura 19 deve guardar o valor “João”. O conjunto de valores dos
atributos de um determinado objeto é chamado de estado. Como visto na Figura 19,
atributos (se existirem) são representados na parte intermediária de uma classe em UML.
          O comportamento de um objeto é definido através de seus métodos. Métodos
definem as habilidades dos objetos. Em outras palavras, as ações que um objeto de uma
classe pode realizar. É comum serem chamados também de comportamento de uma classe
de objetos. Na maioria das vezes, métodos utilizam os atributos da classe como “matéria-
prima” para realizar suas ações, além de também poderem receber parâmetros, como em
um procedimento tradicional. Uma classe pode ter qualquer número de métodos, inclusive
nenhum. Por exemplo, para uma classe carro, poderiam ser definidas ações como andar,
frear, ligar o motor, dentre outras. Como visto na Figura 19, métodos (se existirem) são
representados na parte inferior de uma classe em UML.
         Métodos são definidos nas classes, porém sua execução só ocorre quando o
método é invocado através do objeto. Por exemplo, pode haver uma classe que represente
um automóvel e dois objetos que representem dois modelos diferentes: um Fusca e uma
Ferrari. A classe define um método, que faz com que a velocidade do automóvel seja
reduzida. A utilização de um método frear() deve afetar apenas um objeto em particular.
Todos os carros podem frear, mas a ação em um objeto afeta apenas o objeto em questão.
        Apesar da independência de cada objeto, para que um sistema funcione é
necessário que os objetos interajam. A interação entre objetos ocorre através da troca de
mensagens. Uma mensagem representa o ato de um objeto de uma classe chamar algum
método que outro objeto possua, fazendo com que este comportamento seja executado.
É comum esta ação ser chamada de ativação ou invocação de um método. Em analogia
com a programação estruturada, uma mensagem pode ser vista como uma chamada a
procedimento, inclusive com o retorno de um resultado a partir da execução deste método,
como ilustrado na Figura 20.




                                                                                                             25
Programação II




                                      Figura 20 – Ilustração do envio de uma mensagem para um objeto



                               Para um objeto invocar um método em outro objeto é necessário que obtenha uma
                      referencia ao objeto-alvo. Como cada objeto precisa ser identificado de forma unívoca (ou
                      seja, de forma exclusiva), faz-se então necessário definir um identificador para cada objeto.
                      Tome como exemplo a Figura 21. A classe Estudante define as características gerais de
                      um aluno. O método imprimirNome() é definido para apresentar tanto o nome do aluno,
                      quanto seu curso.




                                                    Figura 21 – Referências para objetos



                              Existem dois objetos que representam dois alunos distintos. Para isso, cada objeto
                      tem um identificador único. Para o aluno cujo nome é Fernando, o identificador do objeto é
                      aluno1, enquanto para o outro aluno, aluno2. Para se mandar uma mensagem para um dos
                      objetos utiliza-se a chamada “sintaxe do ponto” (dot syntax). Esta sintaxe indica que o acesso
                      a um atributo ou método de um objeto deve ser feita utilizando a forma “objeto.método”
                      ou “objeto.atributo”. No nosso exemplo, para chamar o método imprimirNome no objeto
                      aluno1, deve ser utilizada a notação aluno1.imprimirNome(). Dessa forma, representa-se a
                      ativação de uma mensagem neste objeto.


                      2.2. Agregação/Composição

                               A ideia de agregação ou composição estabelece a criação de novas classes de
                      objetos a partir da junção de classes já existentes. Essa ideia de composição é muito comum
                      para se representar relações do tipo todo-parte, como no caso de uma turma ser composta
                      por instâncias de outras classes, como um professor, um conjunto de alunos, dentre outros.
                             Da mesma forma que a classificação/instanciação são processos inversos, para a
                      composição de classes são definidas duas operações diferentes:

26
Programação II



    »   Operação de Agregação: Quando unimos um conjunto de objetos para formarmos
        um novo objeto;
    »   Operação de Decomposição: Quando, analisando um objeto, isolamos cada um de
        seus componentes.
        Veja o seguinte exemplo:




                            Figura 22 – Agregação/Decomposição



        Neste exemplo, a classe Automóvel pode ser decomposta nas classes Placa e Motor.
Este processo, chamado de decomposição, realiza uma análise sobre a classe Automóvel
e aplica um refinamento. Refinar significa deixar ainda mais claro a estrutura de um
determinado conceito. O processo inverso faz uma síntese de conceitos já existentes para
criar um novo conceito.
        Há uma notação especial em UML para representar agregação, como ilustrado e
exemplificado na Figura 23. Um losango vazado é anexado à extremidade de um caminho de
associação ao lado do agregado (o todo) para indicar agregação.




                 Figura 23 – Notação UML para agregação; Tipos de Agregação



       Há uma distinção entre dois tipos de agregação: a agregação compartilhada e a
composição. No primeiro tipo, representado pela ideia de uma disciplina que contem um


                                                                                                       27
Programação II



                      professor e uma sala vinculada, objetos contidos podem existir sem serem parte do objeto
                      que os contém. Em outras palavras, um professor continuará a existir, mesmo que não haja
                      o conceito Disciplina.
                               No caso da composição, objetos contidos não fazem sentido fora do contexto do
                      objeto que os contém. No exemplo apresentado, um pedido contem itens e um Cliente
                      vinculado. Se você destruir o pedido, os itens são destruídos junto, pois eles não tem sentido
                      fora do pedido. Neste caso, o losango anexado à extremidade da classe agregadora deve ser
                      preenchido, e não vazado.


                      2.3. Associações Simples

                               As entidades envolvidas apresentam existências independentes, mas existe uma
                      ligação entre elas. A agregação não é única forma de relacionamento entre objetos e classes.
                      Classes e objetos podem formar associações, que consistem na descrição genérica de uma
                      ou mais ligações entre as classes, permitindo que objetos de uma classe utilizem recursos
                      de outros objetos. Ao se estabelecer associações entre classes, em geral se estabelece o
                      significado de uma classe “usar” ou “possuir” outra. Para representar associações entre
                      classes, UML utiliza uma linha unindo as duas classes. Alguns exemplos de associações são
                      descritas abaixo.




                                                   Figura 24 – Associações entre classes



                               Nos exemplos acima, temos que um cliente está vinculado a um produto, e
                      vice-versa. Uma conta possui um histórico de transações. Um hóspede está vinculado
                      à um quarto. Associações podem ainda ser refinadas inserindo a multiplicidade nos
                      relacionamentos entre classes. Por exemplo, um único cliente pode estar vinculado a zero
                      ou mais (sem limites) pedidos. Um velocista pode participar de zero ou mais corridas, e uma
                      corrida deve ter no mínimo dois e no máximo seis velocistas.


                      2.4. Encapsulamento

                               Um dos aspectos mais positivos da programação modular foi a ideia de
                      encapsulamento de informações. A programação orientada a objetos preserva este
                      conceito. Encapsular dados em OO consiste em separar os aspectos externos de um objeto,
                      os quais são acessíveis a outros objetos, dos detalhes internos de implementação do objeto,
                      os quais permanecem escondidos dos outros objetos. O uso de encapsulamento evita que
                      objetos possuam grandes dependências entre si, de modo que uma simples mudança em
                      um objeto possa trazer grandes efeitos colaterais e problemas para outros objetos.
                              Como vimos no capítulo I, o conceito de encapsulamento não é exclusivo da
                      abordagem de orientação a objetos. Entretanto, a habilidade de se combinar estrutura de
                      dados e comportamento em uma única entidade torna o encapsulamento mais elegante
                      e mais poderoso do que em linguagens convencionais que separam estruturas de dados e
                      comportamento.

28
Programação II



        No paradigma OO, o encapsulamento institui conceitos e regras que ajudam a
promover a modularidade entre objetos. Para isso, o acesso a componentes de um objeto
é controlado e, especialmente, os atributos de um objeto só devem ser modificados pelos
métodos do próprio objeto. Veja como isso ajuda a proteger um programa. Imagine a classe
Conta que representa uma conta corrente, cujos atributos são seu número e seu saldo na
Figura 25.




                          Figura 25 – O benefício do encapsulamento



        De acordo com projeto, o saldo de uma conta não pode ser menor que zero. Mas
da forma como até agora conhecemos classes, o acesso a atributos e métodos é liberado.
Logo, qualquer objeto poderia ter o atributo saldo acessado diretamente, e modificado para
um valor inválido, como representado no exemplo. Para sanar este problema, linguagens
orientadas a objetos oferecem mecanismo que modificam a visibilidade (escopo) de
atributos e métodos. É possível então estabelecer que todos os atributos de uma classe só
possam ser acessados de métodos definidos dentro da própria classe. É dito então que o
escopo deste método é privado à sua classe.
        No nosso exemplo, a modificação do saldo de uma conta só poderá ser feita através
do método debitar(valor) que internamente estabelece regras que não permitem que o
saldo da conta fique negativo.
         A ideia do encapsulamento faz também com que o sistema não dependa das
implementações internas das classes, mas sim de suas interfaces. A interface de um objeto é
representada pelo conjunto de todos os métodos que este objeto oferece a outros objetos.
A interface de um objeto é que é externamente visível, e que protege dados internos, além
de outras operações que não devem ser disponibilizadas ao mundo externo.
         Imagine uma classe que represente o conceito de uma coleção de pessoas, e que
forneça métodos para manipular esta coleção, como inserir uma pessoa, consultar uma
pessoa pelo nome, etc. Internamente, esta classe poderia utilizar diferentes estruturas para
guardar a coleção de pessoas, como um vetor, uma lista dinâmica ou mesmo um banco de
dados. Porém, para quem vai utilizar algum objeto desta classe, isso não importa. O que
importa é que exista um método para inserir, outro para consultar, e assim por diante. Desta
forma, alterações dentro da classe não afetarão o restante do sistema. Por exemplo, pode-
se trocar a implementação interna da classe, mudando de um vetor para o banco de dados.
Se a interface for mantida, os objetos que usam não sofreram nenhum impacto, o que torna
a manutenção mais fácil.
        Por estes motivos, na orientação a objetos é muita utilizada a expressão “programar


                                                                                                           29
Programação II



                      para a interface”. Esta expressão indica a ideia que a interface de um objeto representa
                      um contrato entre uma classe de objetos. Enquanto o contrato for mantido, objetos que
                      dependam dos métodos de uma classe não serão prejudicados.


                      2.5. Generalização/Especialização (Herança)

                               Generalização e especialização são abstrações que permitem o reuso de objetos
                      através da criação de classes de objetos a partir de outras classes. No caso, a especialização
                      é o mecanismo pelo qual pode-se definir uma nova classe de objetos a partir de uma classe
                      já existente. Esta nova classe poderá aproveitar o comportamento e possíveis atributos
                      da classe estendida. A classe sendo refinada é chamada de superclasse ou classe base,
                      enquanto que a versão refinada da classe é chamada uma subclasse ou classe derivada. A
                      generalização é o inverso da especialização. A Figura 26 ilustra esta relação:




                                 Figura 26 – Generalização/Especialização, a base para a Herança entre classes



                              Neste exemplo, a superclasse Estudante é refinada em dois tipos mais específicos, os
                      de graduação e os de pós-graduação. Diz-se que cada classe derivada herda as características
                      de sua classe base. Por conta disso é mais comum essa abstração serem tratadas em
                      linguagens de programação orientadas a objetos como Herança. No nosso exemplo, a classe
                      Estudante poderia ter como atributos: nome ou instituição vinculada, estes também são
                      atributos de estudantes de graduação ou pós-graduação. Cada classe derivada não apenas
                      herda as características de seu ancestral como também pode acrescentar seus atributos e
                      operações específicos, como o curso para o Estudante de Graduação.
                               Em UML, a notação para generalização é representada por uma associação entre
                      superclasse e subclasses, onde um triângulo é posto na extremidade próxima à superclasse
                      (Figura 27).




30
Programação II




      Figura 27 – Representação UML para Herança; Exemplo para uma hierarquia de classes



        É importante salientar que a herança não vale apenas para dados, mas também
para métodos. No mesmo exemplo, a classe Estudante define um método imprimeDados.
Portanto, as subclasses da classe Estudante também herdam este comportamento. Com
isto, embora o método não seja definido na classe EstudanteGraduação ou EstudantePos,
qualquer objeto de uma destas duas classes pode ter o método imprimeDados sendo
invocado.
        A correta chamada de métodos ou o acesso a atributos em classes que
possuam uma relação de herança ocorre através da busca nas classes que participam da
hierarquia. Exemplificando: quando um método é chamado em um objeto de uma classe,
a especificação deste método é procurada na classe deste objeto. Se este método não é
encontrado, busca-se então na definição de sua superclasse, e assim por diante, pois uma
hierarquia de herança pode ser formada por várias classes, recursivamente aplicada a um
número arbitrário de níveis. A Figura 28 exemplifica uma relação de herança em mais de um
nível.




                            Figura 28 – Múltiplos níveis de herança




                                                                                                            31
Programação II



                              Neste exemplo, o Estudante de Graduação além do curso, possui também como
                      atributos herdados a matricula (da classe Estudante) e o nome (da classe Pessoa).
                               Uma subclasse pode também sobrepor uma característica de sua superclasse,
                      o que significa que a nova característica local à subclasse irá substituir a característica de
                      sua superclasse. Neste caso, esta ação é chamada de sobreposição. Ainda no exemplo
                      anterior, a classe Estudante sobrepõe o método imprimeDados da classe Pessoa. Em outras
                      palavras, a execução deste método em objetos da classe Estudante obedecerá a esta nova
                      definição. Note que esta alteração também afeta objetos das classes EstudanteGraduação
                      e EstudantePos. Objetos dos tipos Pessoa e Empregado executam a definição original do
                      método.
                               A definição e uso de herança traz consigo também um princípio muito importante
                      para a orientação a objetos que é o princípio da substituição. Este princípio se baseia no
                      fato que, se uma subclasse herda métodos e atributos de sua superclasse, em qualquer
                      lugar de um programa que você possa utilizar uma instância de superclasse, você também
                      deve poder utilizar uma instância de qualquer subclasse desta classe. Embora pareça
                      complicado, imagine um programa que faz uma chamada ao método imprimeDados de
                      um objeto Pessoa, de acordo com a hierarquia de classes da Figura 27. Pelo princípio da
                      substituição, você pode substituir este objeto Pessoa por qualquer outro objeto que seja
                      instância de alguma subclasse de Pessoa, como Estudante, Empregado, EstudantePos ou
                      EstudanteGradução. Como todos eles vão possuir o método imprimeDados, o programa vai
                      continuar a funcionar sem problemas. Este princípio é muito útil para facilitar a extensão de
                      programas.

                              Herança Simples e Herança Múltipla

                              A herança pode ser de dois tipos: Simples e Múltipla. A herança simples é quando
                      uma classe é subclasse de somente uma superclasse, enquanto a herança múltipla ocorre
                      quando uma classe é subclasse de várias superclasses e, consequentemente, herda as
                      características de cada uma delas. Os exemplos que vimos até agora foram todos de herança
                      simples. A Figura 29 apresenta um exemplo de uma herança múltipla.




                                                  Figura 29 – Exemplo de Herança Múltipla



                              Neste caso, note que a classe VeiculoAnfibio possui duas superclasses, Carro e
                      Barco. Desta forma, ela herda métodos e atributos destas duas classes. Herança múltipla
                      não se limita a apenas duas classes, de acordo com o contexto do mundo que se queira
                      modelar. Porém, a herança múltipla traz um problema: o conflito de atributos ou métodos
                      herdados das superclasses. Em nosso exemplo, note que tanto Carro quanto Barco possuem
                      um método parar. Imagine então o que aconteceria se fosse feita uma chamada ao método
                      parar em um objeto do tipo VeiculoAnfibio. Qual implementação de parar deveria ser
                      chamada?



32
Programação II



         Por conta dessa e de outras questões, a Herança Múltipla não é implementada em
todas linguagens de programação, como no caso de Java. Porém, pode ser encontrada em
outras linguagens como C++ e SmallTalk.


2.6. Polimorfismo

        O termo polimorfismo é originário do grego, e etimologicamente quer dizer “muitas
formas”. Na orientação a objetos, isso significa que um mesmo tipo de objeto, sob certas
condições, pode realizar ações diferentes ao receber uma mesma mensagem. Ou seja,
objetos podem ter reações diferentes ao mesmo estímulo (Figura 30).




         Figura 30 – Polimorfismo: Objetos têm diferentes reações a um mesmo estímulo



        Polimorfismo permite o envio de uma mesma mensagem a objetos distintos, onde
cada objeto responde da maneira mais apropriada para a classe chamadora. No exemplo
da Figura 30, a mesma mensagem “desenhar” pode ser enviada a três objetos distintos: o
quadrado, o círculo e o triângulo. Os três sabem como tratar esta mensagem, porém cada
um realizará ações diferentes.
        Existem dois tipos principais de polimorfismo: a sobrecarga e a sobreposição.
        Na sobrecarga, uma mesma classe de objetos possui métodos com o mesmo nome,
porém quantidade ou tipo de parâmetros diferentes. No momento da chamada do método,
dependendo do parâmetro, um método ou outro será chamado. Por exemplo, a classe
Pessoa (Figura 31) possui dois métodos imprimir. O primeiro recebe apenas um parâmetro,
enquanto o segundo recebe dois.




                              Figura 31 – Sobrecarga de métodos



         Já a sobreposição ocorre somente associada à herança. Quando um método
definido na superclasse não serve da forma original para a subclasse, ele tem de ser
redefinido. Como na redefinição a assinatura deve ser mantida, o novo método sobrepõe o
método definido na superclasse.
       Veja como exemplo a Figura 32. Existem dois tipos de Funcionário: o que recebe
um salário fixo (Empregado) e outro cujo salário é calculado de acordo com suas vendas


                                                                                                         33
Programação II



                      (EmpregadoComissão). O segundo tipo tem as mesmas características do primeiro, portanto
                      convém que se utilize herança para reaproveitar seus dados. Porém, o calculo de seu salário
                      é totalmente diferente. Neste caso, a subclasse modifica (sobrepõe) o comportamento do
                      método que calcula o salário para a classe EmpregadoComissão.




                                                  Figura 32 – Sobreposição de métodos



                               Neste caso, quando um objeto for do tipo Empregado, o calculo do salário obedecerá
                      a regra definida na superclasse. Mas quando o objeto for do tipo EmpregadoComissão, a
                      regra utilizada é aquela que foi redefinida nesta classe. Em resumo:

                          »   O método a ser chamado é aquele pertencente ao objeto o qual a chamada está
                              relacionada;
                          »   Caso o objeto não possua este método, a chamada é transferida para a superclasse,
                              e assim por diante até que o método seja encontrado;
                              Porém, ao contrário da sobreposição, métodos sobrepostos na subclasse precisam
                      ter a mesma assinatura de seus equivalentes na superclasse. Em outras palavras, precisam
                      ter o mesmo nome; o mesmo número de parâmetros e o mesmo tipo de parâmetros de
                      entrada e saída.


                                   Exercícios


                          1. No contexto da programação orientada a objetos, o que é um objeto?
                          2. No contexto da programação orientada a objetos, o que é uma classe? Diga também
                             o que são métodos e variáveis de instância.
                          3. Indique qual é o principal benefício obtido quando os atributos de uma classe não
                             são visíveis a outras classes? Qual é o nome desta técnica de programação?
                          4. Explique o que é o relacionamento de herança entre classes.
                          5. Para você, qual o benefício do polimorfismo no paradigma orientado a objetos?
                          6. Utilizando orientação a objetos, indique quais seriam as classes, seus atributos,
                             métodos e associações para os seguintes sistemas:
                               a) Uma universidade;
                               b) Um acervo de mídias (CDs e DVDs)
                               c) Um filme.




34
Programação II




             Vamos Revisar?


         Neste capítulo, você foi apresentado a uma nova forma de organizar os conceitos
para criação de programas de computador. A orientação a objetos baseia-se em uma
aproximação da forma como os seres humanos organizam e realizam ações no mundo real.
Para isso, novas abstrações como classificação, agregação, associação, dentre outras são
fundamentais para que os programas sejam organizados de forma a permitir um maior reuso
de código e maior flexibilidade de manutenção. Conceitos como classes, objetos, métodos
e atributos são fundamentais em linguagens orientadas a objetos, vão fazer parte do dia a
dia deste curso. A partir deles, conceitos mais avançados como herança e polimorfismo são
gerados, e serão mais detalhados adiante nesta disciplina. Por enquanto, é importante que
os conceitos deste capítulo seja amadurecidos em sua cabeça.




                                                                                                        35
Programação II




                               Capítulo 3


                          O que vamos estudar neste capítulo?

                          Neste capítulo, vamos estudar os seguintes temas:

                      »   Linguagem de Programação Java
                      »   Java Software Development Kit – JSDK
                      »   O ambiente de programação JCreator

                          Metas

                          Após o estudo deste capítulo, esperamos que você consiga:

                      »   Identificar as principais características da Linguagem Java;
                      »   Instalar e configurar o Kit de desenvolvimento necessário para compilar e executar
                          seus programas em Java;
                      »   Instalar o ambiente de programação JCreator;




36
Programação II




Capítulo 3 – A Linguagem Java

             Vamos conversar sobre o assunto?


         Nos capítulos iniciais deste volume você aprendeu sobre a necessidade de
melhorar a forma como organizamos os conceitos em linguagens de programação e como
a orientação a objetos busca melhorar o reuso e a manutenção de programas. Bem, até
agora, tudo foi bastante teórico. Então chegou a hora de começarmos a ver como na prática
isso tudo funciona. Para isto, este capítulo introduz a linguagem de programação orientada
a objetos mais popular no mundo: Java.




1. Introdução
                                                                                                   Você Sabia?
        A linguagem de programação Java tem origem no início da década de 90, dentro
da Sun Microsystems. Na época, uma equipe liderada por Patrick Naughton, Mike Sheridan,
e James Gosling tinha como objetivo projetar uma nova linguagem de programação capaz
de criar softwares capazes de comunicar diferentes dispositivos entre si. Originalmente,
batizou-se esta linguagem de Oak (carvalho, em inglês), em homenagem a um espécie de
árvore que os integrantes do projeto avistavam de sua sala.
        Inicialmente a proposta de interoperabilidade de programas não foi muito bem
aceita pelo mercado, o que então fez com os objetivos fossem modificados. Na época, o        Você sabia que a
                                                                                             linguagem Java tem
uso da Internet estava crescendo vertiginosamente. Foi então que a Sun viu nesta expansão    esse nome devido a
uma oportunidade de usar Oak. A linguagem passaria então a ser voltada para construir        um café?
aplicações para Web. A linguagem foi rebatizada e passou a se chamar Java, sendo             Durante o projeto os
apresentada oficialmente em 1995.                                                            participantes tomava
                                                                                             muito café, e gostavam
       Desde então, Java foi rapidamente adotada pelo mundo, mais rapidamente que            principalmente de
qualquer outra linguagem de programação até então. Grandes fornecedores de tecnologia        um proveniente da
como IBM, Oracle, Netscape, dentre outros, passaram a apoiar Java.                           ilha de Java. No meio
                                                                                             do projeto Green,
        A linguagem evoluiu muito ao longo dos anos. Hoje, mas que uma linguagem,            os projetistas foram
                                                                                             avisados que já havia
Java pode ser vista como uma plataforma de desenvolvimento e execução de programas
                                                                                             uma linguagem com
em diversas plataformas. Você encontra programas Java na Web, dos telefones celulares,       o nome de oak, que
mainframes, cartões inteligentes, dentre outros. Com isso, a linguagem é dividida em 3       inicialmente era o
grandes segmentos:                                                                           escolhido. Com isso, os
                                                                                             projetistas resolveram
    1. JEE (Java Enterprise Edition): indicado para aplicações coorporativas, com            homenagear a ilha que
                                                                                             produzia o café tão
       necessidade gerenciamento de transações, balanceamento de carga, concorrência,        apreciado por todos.
       dentre outros;
    2. JSE (Java Standar Editon): é o ambiente de desenvolvimento mais utilizado. Isso
       porque seu uso é voltado a PCs e servidores, onde há bem mais necessidade de
       aplicações;
    3. JME (Java Micro Edition): é o ambiente de desenvolvimento para dispositivos
       móveis ou portáteis, como telefones celulares e palmtops.
        Hoje, estima-se que haja uma comunidade de mais de quatro milhões de

                                                                                                               37
Programação II



                      programadores Java no mundo. Existem também grupos de usuários Java, chamados JUGs
                      (Java User Groups), que são utilizados para troca de ideias, dúvidas e melhores práticas no
                      uso da tecnologia Java. No Brasil, existem vários, como o DF-JUG (de Brasília) ou CE- JUG(do
                      Ceará). Existem diversos livros publicados sobre a linguagem, além de diversos ambientes
                      de programação e desenvolvimento.



                      2. Características da Linguagem
                             Durante seu projeto, a linguagem Java teve uma série de requisitos que podem se
                      apontados como fatores de seu sucesso.

                          1. Java é orientada a objetos: Java foi baseada no modelo de outras linguagens de
                             programação OO, no caso, Simula67 e SmallTalk. Com isso, os conceitos de herança,
                             polimorfismo e encapsulamento são implementados pela linguagem. A sintaxe e
                             seu sistema de tipos é bem parecido com C e C++, o que facilitou a migração de
                             programação de programadores já acostumados com estas linguagens;
                          2. Java é portável: Este conceito indica que um mesmo programa escrito em Java
                             pode ser executado em diferentes plataformas hardware ou sistema, sem grandes
                             ou nenhuma mudanças. Por conta desta característica, é comum se associar a Java
                             o seguinte jargão: “escreva uma vez, execute em qualquer lugar;
                          3. Java é segura, confiável e robusta: Ao contrário de suas predecessoras, Java não
                             trabalha com ponteiros. Em outras palavras, um programador Java não tem acesso
                             direto a posições de memória, um dos grandes problemas para quem trabalha
                             com linguagens como C ou C++. Java possui um mecanismo de tratamento de
                             exceções em que os erros que possam vir a ocorrer durante operações efetuadas
                             são tratadas paralelamente em outro trecho de código do sistema. Um erro que
                             durante a execução do programa poderá ser capturado sem imprevistos como, por
                             exemplo, acessos inválidos de memória do sistema operacional, ou do gerenciador
                             de arquivos, que podem acarretar problemas como o travamento, desligamento do
                             computador e perda de arquivos significativos;
                          4. Java promove reuso e facilita a manutenabilidade: Java possibilita a criação de
                             componentes reutilizáveis, ou seja, uma vez criadas funcionalidades para os
                             mesmos, estes poderão ser reutilizáveis posteriormente. Com isso é proporcionado
                             um baixo custo de produção e manutenção de códigos gerados com os demais
                             sistemas que venham a ser desenvolvidos;
                          5. Java é distribuída: Java possui a capacidade de compartilhamento de informações
                             possibilitando a distribuição de tal forma que haja processamento em máquinas
                             distintas. Possui integração com o protocolo TCP/IP que facilita a programação para
                             acessos remotos, utilizando protocolos como: HTTP e FTP;
                          6. Java permite a carga dinâmica de aplicações: Java oferece o recurso de que
                             aplicações chamadas applets possam ser carregadas remotamente e executadas no
                             contexto de um browser, ao ler uma página na Web. Ao fazer isso, Java introduziu
                             a interatividade na Web, permitindo que aplicações pudessem ser descarregadas
                             e utilizadas automaticamente por usuários, sem necessidade de instalação, ou
                             atualizações de versões. Ao mesmo tempo, applets possuem um criterioso modelo
                             de segurança que previne o acesso de aplicações remotas a possíveis ações danosas
                             no computador do usuário que rode um applet;
                          7. Java é livre e gratuita: Você não paga nada para criar um programa em Java. O
                             software para execução e construção de programas é disponibilizado gratuitamente

38
Programação II



        na Internet. Além disso, existem vários ambientes gratuitos para facilitar a
        construção e depuração de programas Java.



3. Máquina Virtual Java: o alcance de
portabilidade
          Uma das características mais importantes da linguagem Java é a portabilidade. Para
isto, Java promove o conceito que nada na linguagem deve ser específico de uma plataforma
específica. O que na realidade Java faz, é criar a ideia de um computador abstrato sobre o
qual o programa deve ser executado. Esse computador abstrato é chamado de máquina
virtual Java (JVM).
        Na realidade, a máquina virtual Java é uma especificação fornecida a início pela
Sun, e seu funcionamento une a ideia de compilação e interpretação de programas. Vamos
ver como isso funciona.
        Para criar um programa Java precisamos criar sua especificação através da sintaxe
da linguagem. Como em praticamente toda linguagem de programação isso é feito através
da edição de um arquivo texto.
         A partir de um programa escrito corretamente, a etapa que segue é a compilação do
programa para geração de sua versão executável. Aqui vem uma grande diferença. Em vez
de gerar um arquivo executável que é voltado para um computador ou sistema operacional
específico, Java gera uma versão intermediária do programa, o bytecode.
        O bytecode é um arquivo neutro e independente de plataforma. Ele representa
o programa executável e livre de erros, como uma linguagem de máquina destinada a
um processador virtual especificado pela máquina virtual Java. Desta forma, qualquer
implementação de uma máquina virtual Java deve ser capaz de executar este programa. O
que de fato acontece, pois hoje existem implementações da máquina virtual Java para as
mais diversas plataformas, como Windows, Linux, MacOS, dentre outros (Figura 33).




             Figura 33 – O processo de compilação e execução de um programa Java



        A JVM utiliza o mecanismo de interpretação para executar os bytecodes que
correspondem ao programa originalmente escrito pelo programador. O uso de uma
máquina virtual acarreta em um tempo a mais na execução do programa, o que indica que
programas escritos em Java tendem a ser mais lentos que programas equivalentes escritos
em C ou C++. Porém, a facilidade na migração de um sistema entre diferentes plataformas é
um requisito cada vez mais importante na construção das aplicações modernas. Ou seja, é
um benefício que se paga.
       Além disso, as atuais implementações de JVM fazem uma série de otimizações que
diminuem a diferença em relação à execução de um programa Java e programas compilados
diretamente para uma plataforma específica.



                                                                                                           39
Programacao ii volume1_v_final
Programacao ii volume1_v_final
Programacao ii volume1_v_final
Programacao ii volume1_v_final
Programacao ii volume1_v_final
Programacao ii volume1_v_final
Programacao ii volume1_v_final
Programacao ii volume1_v_final
Programacao ii volume1_v_final
Programacao ii volume1_v_final
Programacao ii volume1_v_final

Contenu connexe

Similaire à Programacao ii volume1_v_final

Educação digital und_01_apresent
Educação digital und_01_apresentEducação digital und_01_apresent
Educação digital und_01_apresentDaniela F Almenara
 
Caderno atividades módulo Elaboração de Projetos
Caderno atividades módulo Elaboração de ProjetosCaderno atividades módulo Elaboração de Projetos
Caderno atividades módulo Elaboração de Projetosproinfoundimeparaiba
 
6 ano computacao e eu estudante
6 ano computacao e eu estudante6 ano computacao e eu estudante
6 ano computacao e eu estudanteMarcela Graciuti
 
6 ano computacao e eu estudante
6 ano computacao e eu estudante6 ano computacao e eu estudante
6 ano computacao e eu estudanteMarcela Graciuti
 
Projeto: NAVEGANDO EM DIREÇÃO AO FUTURO
Projeto:  NAVEGANDO EM DIREÇÃO AO FUTURO Projeto:  NAVEGANDO EM DIREÇÃO AO FUTURO
Projeto: NAVEGANDO EM DIREÇÃO AO FUTURO LABICEDCOM
 
Apresentação unidade ii
Apresentação unidade ii Apresentação unidade ii
Apresentação unidade ii Danuza Rodrigues
 
Apresentacao curso introedudigital 40h - 2012
Apresentacao curso introedudigital 40h - 2012Apresentacao curso introedudigital 40h - 2012
Apresentacao curso introedudigital 40h - 2012Dirce Reges Crispim Sousa
 
Unidade 1 - Curso Introdução à Educação Digital
Unidade 1 - Curso Introdução à Educação DigitalUnidade 1 - Curso Introdução à Educação Digital
Unidade 1 - Curso Introdução à Educação DigitalAna Lúcia Lemes Nunes Silva
 
ATPS - Programação Estruturada II
ATPS - Programação Estruturada IIATPS - Programação Estruturada II
ATPS - Programação Estruturada IIthomasdacosta
 
(LP2) Tópico 00 - Apresentação da Disciplina
(LP2) Tópico 00 - Apresentação da Disciplina(LP2) Tópico 00 - Apresentação da Disciplina
(LP2) Tópico 00 - Apresentação da DisciplinaFabricio Narcizo
 
Pensamento Computacional, Programação e Robótica no 1º CEB
Pensamento Computacional, Programação e Robótica no 1º CEBPensamento Computacional, Programação e Robótica no 1º CEB
Pensamento Computacional, Programação e Robótica no 1º CEBJoão Piedade
 
Orientação a objetos java
Orientação a objetos javaOrientação a objetos java
Orientação a objetos javavicnetepc
 
Intro micro software
Intro micro softwareIntro micro software
Intro micro softwareTiago
 
Ihc2016.2 aula 0 apresentação da disciplina de IHC
Ihc2016.2 aula 0 apresentação da disciplina de IHCIhc2016.2 aula 0 apresentação da disciplina de IHC
Ihc2016.2 aula 0 apresentação da disciplina de IHCTicianne Darin
 

Similaire à Programacao ii volume1_v_final (20)

Educação digital und_01_apresent
Educação digital und_01_apresentEducação digital und_01_apresent
Educação digital und_01_apresent
 
Unidade 1
Unidade 1Unidade 1
Unidade 1
 
Tecnologias no cotidiano
Tecnologias no cotidianoTecnologias no cotidiano
Tecnologias no cotidiano
 
Tecnologias no cotidiano
Tecnologias no cotidianoTecnologias no cotidiano
Tecnologias no cotidiano
 
Caderno atividades módulo Elaboração de Projetos
Caderno atividades módulo Elaboração de ProjetosCaderno atividades módulo Elaboração de Projetos
Caderno atividades módulo Elaboração de Projetos
 
Unidade 1
Unidade 1Unidade 1
Unidade 1
 
6 ano computacao e eu estudante
6 ano computacao e eu estudante6 ano computacao e eu estudante
6 ano computacao e eu estudante
 
6 ano computacao e eu estudante
6 ano computacao e eu estudante6 ano computacao e eu estudante
6 ano computacao e eu estudante
 
Projeto: NAVEGANDO EM DIREÇÃO AO FUTURO
Projeto:  NAVEGANDO EM DIREÇÃO AO FUTURO Projeto:  NAVEGANDO EM DIREÇÃO AO FUTURO
Projeto: NAVEGANDO EM DIREÇÃO AO FUTURO
 
Apresentação unidade ii
Apresentação unidade ii Apresentação unidade ii
Apresentação unidade ii
 
Apresentacao curso introedudigital 40h - 2012
Apresentacao curso introedudigital 40h - 2012Apresentacao curso introedudigital 40h - 2012
Apresentacao curso introedudigital 40h - 2012
 
Unidade 1 - Curso Introdução à Educação Digital
Unidade 1 - Curso Introdução à Educação DigitalUnidade 1 - Curso Introdução à Educação Digital
Unidade 1 - Curso Introdução à Educação Digital
 
ATPS - Programação Estruturada II
ATPS - Programação Estruturada IIATPS - Programação Estruturada II
ATPS - Programação Estruturada II
 
(LP2) Tópico 00 - Apresentação da Disciplina
(LP2) Tópico 00 - Apresentação da Disciplina(LP2) Tópico 00 - Apresentação da Disciplina
(LP2) Tópico 00 - Apresentação da Disciplina
 
Pensamento Computacional, Programação e Robótica no 1º CEB
Pensamento Computacional, Programação e Robótica no 1º CEBPensamento Computacional, Programação e Robótica no 1º CEB
Pensamento Computacional, Programação e Robótica no 1º CEB
 
Orientação a objetos java
Orientação a objetos javaOrientação a objetos java
Orientação a objetos java
 
Intro micro software
Intro micro softwareIntro micro software
Intro micro software
 
ACM Lost171
ACM Lost171ACM Lost171
ACM Lost171
 
Poo frank
Poo frankPoo frank
Poo frank
 
Ihc2016.2 aula 0 apresentação da disciplina de IHC
Ihc2016.2 aula 0 apresentação da disciplina de IHCIhc2016.2 aula 0 apresentação da disciplina de IHC
Ihc2016.2 aula 0 apresentação da disciplina de IHC
 

Plus de CLEAN LOURENÇO

Produtos multiídia rosinalva lopes
Produtos multiídia rosinalva lopesProdutos multiídia rosinalva lopes
Produtos multiídia rosinalva lopesCLEAN LOURENÇO
 
Produção midias poloananas_cleanlourenco
Produção midias poloananas_cleanlourencoProdução midias poloananas_cleanlourenco
Produção midias poloananas_cleanlourencoCLEAN LOURENÇO
 
IV DIA D DA MATEMÁTICA 2011
IV DIA D DA MATEMÁTICA  2011IV DIA D DA MATEMÁTICA  2011
IV DIA D DA MATEMÁTICA 2011CLEAN LOURENÇO
 
Evidências do projeto geometria e artes
Evidências do projeto geometria e artesEvidências do projeto geometria e artes
Evidências do projeto geometria e artesCLEAN LOURENÇO
 
Avaliação 6° ano - 2° b - 2011
Avaliação   6° ano - 2° b - 2011Avaliação   6° ano - 2° b - 2011
Avaliação 6° ano - 2° b - 2011CLEAN LOURENÇO
 
Matematica discreta fasciculo_3_v06
Matematica discreta fasciculo_3_v06Matematica discreta fasciculo_3_v06
Matematica discreta fasciculo_3_v06CLEAN LOURENÇO
 
Matematica discreta fasciculo_1_v7
Matematica discreta fasciculo_1_v7Matematica discreta fasciculo_1_v7
Matematica discreta fasciculo_1_v7CLEAN LOURENÇO
 
Texto Dengue - Tocantins
Texto   Dengue - TocantinsTexto   Dengue - Tocantins
Texto Dengue - TocantinsCLEAN LOURENÇO
 
Avaliação 8° ano 2° av
Avaliação 8° ano   2° avAvaliação 8° ano   2° av
Avaliação 8° ano 2° avCLEAN LOURENÇO
 
Atividade 1 números inteiros
Atividade 1   números inteirosAtividade 1   números inteiros
Atividade 1 números inteirosCLEAN LOURENÇO
 
Atividade de matemática tratamento da informação - dengue
Atividade de matemática    tratamento da informação - dengueAtividade de matemática    tratamento da informação - dengue
Atividade de matemática tratamento da informação - dengueCLEAN LOURENÇO
 
Atividade números inteiros operações
Atividade números inteiros    operaçõesAtividade números inteiros    operações
Atividade números inteiros operaçõesCLEAN LOURENÇO
 
Banco de dados_-_volume_4_v10
Banco de dados_-_volume_4_v10Banco de dados_-_volume_4_v10
Banco de dados_-_volume_4_v10CLEAN LOURENÇO
 
Exemplo projeto-bd-assunto-2a-aval-bsi-lc
Exemplo projeto-bd-assunto-2a-aval-bsi-lcExemplo projeto-bd-assunto-2a-aval-bsi-lc
Exemplo projeto-bd-assunto-2a-aval-bsi-lcCLEAN LOURENÇO
 
Livro banco de_dados_volume_03
Livro banco de_dados_volume_03Livro banco de_dados_volume_03
Livro banco de_dados_volume_03CLEAN LOURENÇO
 
Livro banco de_dados_volume_02
Livro banco de_dados_volume_02Livro banco de_dados_volume_02
Livro banco de_dados_volume_02CLEAN LOURENÇO
 
Projeto reforço escolar
Projeto reforço escolarProjeto reforço escolar
Projeto reforço escolarCLEAN LOURENÇO
 
Projeto de arte e matemática
Projeto de arte e matemáticaProjeto de arte e matemática
Projeto de arte e matemáticaCLEAN LOURENÇO
 

Plus de CLEAN LOURENÇO (20)

Produtos multiídia rosinalva lopes
Produtos multiídia rosinalva lopesProdutos multiídia rosinalva lopes
Produtos multiídia rosinalva lopes
 
Produção midias poloananas_cleanlourenco
Produção midias poloananas_cleanlourencoProdução midias poloananas_cleanlourenco
Produção midias poloananas_cleanlourenco
 
V1nmerosnaturais 1.swf
V1nmerosnaturais 1.swfV1nmerosnaturais 1.swf
V1nmerosnaturais 1.swf
 
IV DIA D DA MATEMÁTICA 2011
IV DIA D DA MATEMÁTICA  2011IV DIA D DA MATEMÁTICA  2011
IV DIA D DA MATEMÁTICA 2011
 
Evidências do projeto geometria e artes
Evidências do projeto geometria e artesEvidências do projeto geometria e artes
Evidências do projeto geometria e artes
 
Avaliação 6° ano - 2° b - 2011
Avaliação   6° ano - 2° b - 2011Avaliação   6° ano - 2° b - 2011
Avaliação 6° ano - 2° b - 2011
 
Matematica discreta fasciculo_3_v06
Matematica discreta fasciculo_3_v06Matematica discreta fasciculo_3_v06
Matematica discreta fasciculo_3_v06
 
Matematica discreta fasciculo_1_v7
Matematica discreta fasciculo_1_v7Matematica discreta fasciculo_1_v7
Matematica discreta fasciculo_1_v7
 
Texto Dengue - Tocantins
Texto   Dengue - TocantinsTexto   Dengue - Tocantins
Texto Dengue - Tocantins
 
7º ano ângulos
7º ano    ângulos7º ano    ângulos
7º ano ângulos
 
Avaliação 8° ano 2° av
Avaliação 8° ano   2° avAvaliação 8° ano   2° av
Avaliação 8° ano 2° av
 
Atividade 1 números inteiros
Atividade 1   números inteirosAtividade 1   números inteiros
Atividade 1 números inteiros
 
Atividade de matemática tratamento da informação - dengue
Atividade de matemática    tratamento da informação - dengueAtividade de matemática    tratamento da informação - dengue
Atividade de matemática tratamento da informação - dengue
 
Atividade números inteiros operações
Atividade números inteiros    operaçõesAtividade números inteiros    operações
Atividade números inteiros operações
 
Banco de dados_-_volume_4_v10
Banco de dados_-_volume_4_v10Banco de dados_-_volume_4_v10
Banco de dados_-_volume_4_v10
 
Exemplo projeto-bd-assunto-2a-aval-bsi-lc
Exemplo projeto-bd-assunto-2a-aval-bsi-lcExemplo projeto-bd-assunto-2a-aval-bsi-lc
Exemplo projeto-bd-assunto-2a-aval-bsi-lc
 
Livro banco de_dados_volume_03
Livro banco de_dados_volume_03Livro banco de_dados_volume_03
Livro banco de_dados_volume_03
 
Livro banco de_dados_volume_02
Livro banco de_dados_volume_02Livro banco de_dados_volume_02
Livro banco de_dados_volume_02
 
Projeto reforço escolar
Projeto reforço escolarProjeto reforço escolar
Projeto reforço escolar
 
Projeto de arte e matemática
Projeto de arte e matemáticaProjeto de arte e matemática
Projeto de arte e matemática
 

Programacao ii volume1_v_final

  • 1. UNIVERSIDADE FEDERAL RURAL DE PERNAMBUCO (UFRPE) COORDENAÇÃO GERAL DE EDUCAÇÃO A DISTÂNCIA (EAD/UFRPE) Programação II Fernando Antonio Mota Trinta Volume 1 Recife, 2010
  • 2. Universidade Federal Rural de Pernambuco Reitor: Prof. Valmar Corrêa de Andrade Vice-Reitor: Prof. Reginaldo Barros Pró-Reitor de Administração: Prof. Francisco Fernando Ramos Carvalho Pró-Reitor de Extensão: Prof. Paulo Donizeti Siepierski Pró-Reitor de Pesquisa e Pós-Graduação: Prof. Fernando José Freire Pró-Reitor de Planejamento: Prof. Rinaldo Luiz Caraciolo Ferreira Pró-Reitora de Ensino de Graduação: Profª. Maria José de Sena Coordenação Geral de Ensino a Distância: Profª Marizete Silva Santos Produção Gráfica e Editorial Capa e Editoração: Allyson Vila Nova, Rafael Lira, Italo Amorim e Gláucia Fagundes Revisão Ortográfica: Marcelo Melo Ilustrações: Allyson Vila Nova Coordenação de Produção: Marizete Silva Santos
  • 3. Sumário Apresentação................................................................................................................. 4 Conhecendo o Volume 1 ................................................................................................ 5 Capítulo 1 – Introdução a Orientação a Objetos ............................................................. 7 1. Introdução ...................................................................................................................7 2. Evolução das Linguagens de Programação ..................................................................8 3. Paradigmas de Programação .....................................................................................10 Capítulo 2 – Orientação a Objetos: conceitos principais ............................................... 22 1. Introdução .................................................................................................................22 2. Abstração ...................................................................................................................23 Capítulo 3 – A Linguagem Java ..................................................................................... 37 1. Introdução .................................................................................................................37 2. Características da Linguagem ....................................................................................38 3. Máquina Virtual Java: o alcance de portabilidade .....................................................39 4. Codificando um primeiro programa Java ...................................................................40 5. JSDK – Java Software Development Kit ......................................................................42 6. JCreator: Ambiente de programação de iniciantes ....................................................44 Conheça o Autor .......................................................................................................... 50
  • 4. Apresentação Caro(a) Cursista, Seja bem-vindo(a) ao curso de Programação II. Este curso é composto por 4 volumes. Neste primeiro volume, vamos estudar a teoria e os principais conceitos relacionados ao paradigma de programação baseado em objetos. Além de apresentar suas vantagens em relação a outros paradigmas de programação, será também apresentada a linguagem de programação Java, a ser utilizada no curso para atividades práticas, como exemplos e exercícios. O segundo volume é dedicado em sua totalidade à sintaxe Java, seu sistema de tipos, operadores lógicos, comandos de decisão e repetição. No terceiro volume você aprenderá a utilizar os conceitos de orientação a objetos utilizando a sintaxe apresentada no volume anterior. Por fim, no quarto e último volume serão abordados assuntos ainda mais avançados, como a ideia de herança, polimorfismo e tratamento de exceções. Bons estudos! Fernando Trinta Professor Autor 4
  • 5. Programação II Conhecendo o Volume 1 Neste primeiro volume, você irá encontrar o Módulo 1 da disciplina Programação II. Para facilitar seus estudos, veja a organização deste primeiro módulo. Módulo 1 - Uma Introdução ao Paradigma Orientado a Objetos Carga Horária do Módulo 1: 15 h Objetivo do Módulo 1: Introduzir o paradigma de programação orientada a objetos, a partir de um histórico evolutivo dos paradigmas de programação, ressaltando seus benefícios em relação aos demais. Apresentar os principais conceitos do paradigma orientado a objetos. Introduzir a linguagem de programação orientada a objetos Java, que será utilizada no curso para utilização prática da teoria explanada. Conteúdo Programático do Módulo 1 » Introdução (Evolução dos paradigmas computacionais. O problema da complexidade. A ideia da abstração. Uma nova forma de encarar o problema: Objetos. Vantagens.) » Conceitos Fundamentais do Paradigma OO (Objetos. Classes. Métodos. Atributos. Mensagens. Polimorfismo. Herança.) » A linguagem de Programação Java (Histórico. Estrutura do código em Java. Compilação. Execução. O método main(). Escrevendo na tela. Independência de Plataforma/Máquina Virtual. Ambientes de programação. 5
  • 6. Programação II Capítulo 1 O que vamos estudar neste capítulo? Neste capítulo, vamos estudar os seguintes temas: » Introdução ao Paradigma Orientado a Objetos. » Evolução dos paradigmas computacionais. » O problema da complexidade. » A ideia da abstração. » Uma nova forma de encarar o problema: Objetos. » Vantagens e Desvantagens do Paradigma Orientado a Objetos. Metas Após o estudo deste capítulo, esperamos que você consiga: » Identificar as principais características do paradigma de programação orientado a objetos. » Descrever as vantagens do paradigma orientado a objetos em relação aos demais paradigmas. 6
  • 7. Programação II Capítulo 1 – Introdução a Orientação a Objetos Vamos conversar sobre o assunto? Caro(a) Cursista, é indiscutível o papel que a tecnologia da informação tem hoje na sociedade moderna. Praticamente toda a economia mundial está fortemente ligada a sistemas computacionais que gerenciam bancos, sistemas comerciais, órgãos públicos, dentre outros. Você alguma vez parou para pensar em como estes sistemas foram e continuam sendo construídos?! Não?! Então é hora de você começar a refletir sobre como se dá o processo de construção dos programas que realizam boa parte dos complexos sistemas computacionais modernos. E para isto, nós vamos abordar neste volume um pouco sobre o modelo de programação mais difundido atualmente, o paradigma baseado em objetos. Vamos lá? 1. Introdução Nas últimas décadas, a sociedade moderna vem cada vez mais sendo influenciada por sistemas de informação baseados em computador. Desde sistemas de comércio eletrônico, passando por jogos de computador e chegando até complexos sistemas militares, o mundo moderno é cada vez mais refém da tecnologia e dos sistemas de informação. Você consegue se imaginar em um mundo hoje sem computadores? Sem Internet? É difícil de imaginar. Este parece ser um caminho sem volta que fica ainda mais visível ao passo que nos últimos anos têm crescido o uso de aplicações em dispositivos móveis, como celulares, uso de novas aplicações baseadas em tecnologias inovadoras, como GPS, dentre outros. É inegável que as possibilidades do uso de novas tecnologias são importantes facilitadores para a vida moderna, como no caso de você querer utilizar o seu celular para, baseado na sua atual localização, descobrir qual a farmácia mais próxima ou o melhor caminho para chegar a determinado lugar. Porém, do ponto de vista de quem constrói os novos sistemas, isso tem se tornado um pesadelo, uma vez aumenta a complexidade destas aplicações. Construir as aplicações atuais requer uma série de passos que ajudem a tratar a complexidade destes sistemas. Estes passos e as pessoas que são envolvidas no desenvolvimento de sistemas criaram uma disciplina, conhecida hoje como Engenharia de Software. Esta disciplina ou processo de desenvolvimento concentra as atividades de entender o que um sistema deve fazer (análise), propor uma solução computacional (projeto) e desenvolver esta solução (implementar/codificar) (Figura 1). Esta última fase está diretamente relacionada ao tema desta disciplina: criar aplicações a partir de uma linguagem de programação. Figura 1 – Processo Resumido de Desenvolvimento de Aplicações 7
  • 8. Programação II A ideia de codificar representa uma forma de escrever por meio de uma linguagem de programação, o projeto da solução proposta nas fases anteriores da engenharia de software. Informalmente, uma linguagem de programação pode ser definida como um conjunto limitado de instruções (vocabulário), associado a um conjunto de regras (sintaxe) que define como as instruções podem ser associadas. Ou seja, como se pode compor os programas para a resolução de um determinado problema. Os programas escritos em uma linguagem de programação são então traduzidos para uma linguagem de máquina, que é compreendida pelo computador. O resultado desta conversão são programas executáveis que realizam uma série de ações, como solicitar dados, realizar cálculos específicos ou apresentar dados para usuários. Ao longo dos anos, foram desenvolvidas (e continuam sendo) uma grande quantidade de linguagens de programação, algumas de uso mais geral e outras concebidas para áreas de aplicação específicas. Porém, apesar de suas diferenças, estas linguagens são geralmente agrupadas de acordo com as características principais que indicam como um programador (quem escreve o programa) enxerga a forma de organizar os programas. As diferentes maneiras como uma linguagem organiza seus conceitos é chamada de paradigma de programação. Dentre alguns dos mais conhecidos paradigmas de programação podem- se citar: paradigma imperativo, paradigma estruturado e o paradigma orientado a objetos. A tabela a seguir indica o índice de popularidade dos principais paradigmas de programação existentes: Tabela 1 – Distribuição de Paradigmas segundo índice de popularidade [Fonte: http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html] Paradigma Indice de Popularidade Orientado a Objetos 54,6% Procedural 41,5% Funcional 2,8% Lógico 1,1% Neste momento, caro(a) cursista, você pode se perguntar: para que diferentes paradigmas? Para responder esta questão é necessário voltar no tempo e entender como as linguagens de programação evoluíram ao longo dos anos. 2. Evolução das Linguagens de Programação 2.1. A linguagem de máquina e a linguagem montadora Um computador é organizado em um conjunto de circuitos eletrônicos. Desta forma, seu controle é feito ainda através de uma forma bem primitiva, baseado em um sistema binário para representação de dados e operações. Esta representação é chamada de código binário ou linguagem de máquina, por ser compreendida e executada no hardware do computador. Esta linguagem consiste de uma grande sequência de números (1s e 0s), que instruem os computadores a realizar suas operações mais elementares, uma de cada vez. A figura a seguir apresenta um trecho de um possível programa em linguagem de máquina. 8
  • 9. Programação II Figura 2 – Código de Máquina Criar programas em código binário é impraticável. Para facilitar a construção dos programas, uma nova linguagem de programação foi proposta, onde eram utilizadas abreviações para representar as operações elementares. As linguagens que seguiram esta estratégia foram chamadas linguagens montadoras ou assembly. Em Assembly, em vez de números binários, utiliza-se palavras abreviadas, chamadas também de mnemônicos, indicando a operação a ser realizada. Estas linguagens estavam mais próximas do entendimento dos humanos, e através de um programa chamado montador, o código binário era gerado e podia a ser executado nos computadores da época. Abaixo são apresentados dois exemplos de instruções Assembly: » MOV R1, R2 – A instrução MOV (abreviatura do termo em inglês MOVE) recebe como parâmetros, dois registradores: R1 e R2. Sua execução determina a cópia do conteúdo de R2 para R1 (equivalente R1:=R2, sendo R1 e R2 equivalente a duas variáveis); » ADD R1, R2 – A instrução ADD (abreviatura de ADDITION) recebe como parâmetro, dois registradores como parâmetros: R1 e R2. Sua execução adiciona o conteúdo de R1 ao de R2 e o resultado é armazenado em R1 (equivalente à instrução Pascal R1:=R1+R2). Utilizando estes comandos, os programadores utilizaram Assembly para realizar seus programas. Por exemplo, para somar dois inteiros, um programa em Assembly poderia ser escrito através da rotina descrita abaixo. MOV AX,B ; registro AX recebe o valor de memória contida na variável B ADD AX,C ; AX recebe a soma de AX (valor de B) com o valor de C MOV A,AX ; variável A recebe valor de AX Dá para verificar que o mesmo ainda está bem próximo da linguagem da máquina que do homem. Difícil de entender!? Bastante! Porém, isso na época permitiu que se facilitasse a forma de se construir os programas de computador. 2.2. Aumentando o nível de abstração das linguagens O uso dos computadores foi se popularizando. Com isso, novas aplicações foram propostas para os computadores que surgiram. Com isso, tornou-se necessário facilitar ainda mais a forma como os programas de computadores eram escritos. Surgiram então as chamadas linguagens de programação de alto nível, onde uma única instrução poderia ser utilizada para realizar várias operações elementares do computador. Um programa tradutor chamado compilador transformava o código em alto nível em linguagem de máquina. Programas passaram a ser escritos em uma linguagem mais próxima da linguagem natural e utilizavam notações matemáticas semelhantes ao cotidiano das pessoas. Um programa para calcular o fatorial de um número poderia ser escrito como na figura a seguir. 9
  • 10. Programação II int fatorial(int n) { if (n == 0) return 1; else{ fat = 1; for (int i=2:i<=n){ fat = fat * i; } return fat; } } Figura 3 – Trecho de um programa para cálculo de um fatorial escrito na linguagem C Se mesmo para você esta versão em uma linguagem de alto nível ainda seja incompreensível, pelo menos se percebe que são utilizados menos construções para se realizar a mesma tarefa que em uma linguagem montadora. Desta forma, os programas ficaram mais fáceis de serem compreendidos por nós, humanos. Isto facilitou bastante a programação e, principalmente, a manutenção e correção de erros nos programas. Várias foram as linguagens de alto nível propostas. Dentre algumas, pode-se citar Fortran, Pascal, Basic e C. Algumas delas são bem populares ainda hoje. O surgimento das linguagens de alto nível auxiliou programadores a construir programas mais enxutos, mas fáceis de compreender e também de corrigir erros... Mas onde está o conceito de paradigma nesta história?! Vamos lá então... 3. Paradigmas de Programação 3.1. Paradigma Imperativo Como vimos anteriormente, um paradigma de programação explica como elementos que compõem um programa são organizados e interagem entre si. No caso das linguagens montadoras ou das linguagens de alto nível, a construção dos programas é realizada através de instruções que indicam o que o computador deve realizar. A diferença é que para linguagens montadoras, o programador precisava ser muito mais detalhista que em uma linguagem de alto nível. Um simples comando na linguagem C era equivalente a dezenas de linhas em uma linguagem de baixo nível. Porém, a ideia era a mesma: um conjunto de instruções que ilustram uma estratégia de um ser humano em “COMO” resolver um problema. Esta forma de organizar os programas estabelece um primeiro paradigma de programação conhecido: o paradigma imperativo. Programar um computador neste paradigma significa “dar-lhe ordens” que são executadas sequencialmente. O paradigma imperativo é profundamente influenciado pela arquitetura como os próprios computadores são organizados, a arquitetura de von Neumann. Neste modelo, você deve pensar em um programa como um computador que tem memória que guarda um estado por meio de 10
  • 11. Programação II dados (variáveis), e que recebe instruções que modificam e apresentam estes dados, como ilustrado na figura a seguir: Figura 4 – Modelo Imperativo de programação Como todas as arquiteturas de computadores existentes hoje se baseiam na arquitetura de Von Neumann, os ambientes de execução das linguagens imperativas são bastante eficientes. Porém, mesmo assim, programas escritos no paradigma imperativo ainda são muito detalhistas, o que requer um grande esforço na construção e, principalmente, na manutenção dos programas. Conforme a complexidade dos programas aumenta, a legibilidade, ou seja, a facilidade com que os programas podem ser lidos e entendidos, torna-se também mais difícil. Com isso, a manutenção continuou sendo um problema, e erros acabavam sendo introduzidos sem querer durante o processo de depuração (correção) de programas. 3.2. Paradigma Procedural Uma evolução do paradigma imperativo foi a percepção que certas sequencias de instruções que são repetidas em vários pontos de um mesmo programa. Estes sequências de passos poderiam ser agrupadas em procedimentos e funções (também chamados de sub- rotinas) definidas pelo programador e serem chamadas de diversos pontos do programa, como no caso de criarmos uma função que calcule o valor do fatorial de número (Figura 5). Por esta característica, o paradigma imperativo também é conhecido na literatura como o paradigma procedural. Figura 5 – Paradigma Imperativo VS Paradigma Procedural O paradigma procedural foi durante muitos anos o padrão para linguagens de programação. Este paradigma acabou influenciando também a forma como a própria análise e projeto das aplicações eram realizados. O paradigma procedural induzia que sistemas mais complexos precisavam ser “quebrados” em partes menores, mas fáceis de lidar. Este princípio de “dividir para conquistar” é a abordagem padrão que os desenvolvedores de sistemas utilizam para lidar com sistemas complexos. No caso do paradigma procedural, o sistema era dividido em muitas funções que representavam as diversas funcionalidades que o programa tinha que fazer. Isso era 11
  • 12. Programação II repetido até se chegar a um nível que as funções eram claras o suficiente para entender seu funcionamento, ou mesmo para serem reaproveitadas em diferentes pontos de um programa. Com procedimentos, funções menores eram mais fáceis de entender, além de facilitar eventuais correções de um programa, em caso de erros. De certa forma, esta abordagem de lidar com a complexidade também lida com um conceito chave para a construção de sistemas e a programação de aplicações: a abstração. A ideia de abstração faz com que os desenvolvedores concentrem seus esforços no que é relevante, deixando detalhes irrelevantes para serem tratados mais tarde. Abstração dentro de um paradigma de programação indica como os problemas são encarados. Os conceitos utilizados para resolver estes problemas são as abstrações utilizadas por um paradigma. No caso do paradigma procedural, as abstrações utilizadas para decompor um problema complexo são as sub-rotinas (funções e/ou procedimentos). O uso de sub-rotinas separa dados (variáveis) e operações (procedimentos) sobre os dados, onde a ideia de funções e procedimentos manipulando um conjunto de dados surgiu como um modelo natural para representar como as aplicações. Porém, esta abordagem também apresenta seus problemas. Primeiro, o caminho de execução do programa ficou mais complexo devido à chamada de funções e procedimentos em diversas partes do código. A confusão de chamadas e desvios era tão grande que se criou um termo específico para os programas mal-estruturados a partir de várias chamadas de sub-rotinas, o “código espaguete” (Figura 6). Figura 6 – O código espaguete [Fonte: http://www.yourdictionary.com/images/computer/SPAGETI.GIF] No entanto, o maior problema está relacionado com a separação de dados e procedimentos, pois várias partes de um mesmo programa podiam alterar os valores de variáveis compartilhadas. Em muitos casos, a modificação de uma variável por uma sub-rotina causava a falha na execução de outra sub-rotina que dependia do valor da mesma variável. 12
  • 13. Programação II Além disso, como procedimentos utilizavam valores em variáveis separadas, uma alteração na representação de uma variável poderia exigir uma alteração em cascata em todas as sub- rotinas que dependessem deste valor. Ou seja, um pesadelo para o programador! Figura 7 – Relação entre dados e procedimentos no paradigma procedural Vejamos isso em exemplo mais claro, como o cálculo de uma folha de pagamento de uma empresa. Neste caso, os dados relativos a cada um dos funcionários ficariam espalhados no programa. Seria necessário recuperar estes dados para cada funcionário obter e então realizar o processamento do cálculo da folha de pagamento (Figura 8). Este processamento seria representado por uma função ou uma sub-rotina. Figura 8 – Cálculo de uma folha de pagamento no paradigma procedural Com o aumento da complexidade das aplicações, o gerenciamento entre procedimentos e dados dispersos criava um pesadelo para os programadores que precisavam realizar manutenções no sistema. Modificações em um dado poderiam desencadear um processo de atualização em vários procedimentos. Figura 9 – Dificuldade do gerenciamento de dados e procedimentos no paradigma procedural Além disso, verificou-se que ao longo dos anos, os procedimentos mudavam muito mais que os dados manipulados. Como exemplo, as regras que podem ser associadas ao cálculo do salário de um funcionário variam muito mais que os dados do funcionário, como seu nome ou seu cargo. Desta forma, era necessária uma nova forma de organizar os sistemas. 13
  • 14. Programação II 3.3 Programação Modular e Estruturada Para tentar melhorar as deficiências do paradigma procedural, surgiu então a programação modular. Nesta abordagem, o programa é dividido em vários componentes ou módulos. Ao contrário do paradigma procedural, módulos combinam dados e procedimentos. Um módulo é composto de dados que são manipulados pelos procedimentos deste módulo. Cada módulo fornece um conjunto de procedimentos para que outras partes de um programa possam acessar dados internos de um módulo. Este conjunto de procedimentos ou funções é conhecido como interface do módulo. Desta forma, dados internos de um módulo são protegidos contra manipulações indevidas de outros módulos, em um princípio conhecido como encapsulamento. Estas características trouxeram vantagens em relação aos seus predecessores. Dentre algumas, pode-se citar: » Estrutura do programa fica mais clara ao agrupar funções e variáveis relacionadas em um mesmo módulo; » Possibilidade de alterar módulos separadamente. Uma vez que cada módulo preserve sua interface visualizada por outros módulos, modificações internas e novos procedimentos podem ser incluídos; » O acesso a dados internos de um módulo é feito através de sua interface. Com isso, tem-se um maior controle sobre operações indevidas sobre estes dados. Por exemplo, é possível verificar se um dado pode ou não ser modificado para um determinado valor, antes de se efetivar a mudança. Este estilo de programação também muito referenciada como programação estruturada, devido a uma melhor organização dos conceitos utilizados nos programas. A programação estruturada tornou-se um sucesso e, a partir de seus conceitos, métodos de modelagem e análise foram propostos para facilitar o projeto das novas aplicações que surgiam na época em que surgiu a programação estruturada, como a Análise Estruturada de Tom DeMarco, e a Análise Estruturada Moderna, de Edward Yourdon. Com as ideias de módulos, encapsulamento e interfaces, a programação modular permitiu um melhor aproveitamento e distribuição de programas. Os módulos construídos por um programador poderiam ser reaproveitados por outros programadores, sem a necessidade de se entregar código-fonte. Bastava que os programadores que desejassem utilizar um módulo soubesse a interface deste módulo. Imagine um módulo como uma biblioteca de funções. Poderia haver um módulo para fazer, por exemplo, a verificação se um CPF é válido ou não. A única coisa que um programador precisaria saber é que este módulo possui uma função chamada valida_cpf, que recebe como parâmetro um número de 11 dígitos e retorna verdadeiro se este número representa um CPF válido. Para os programadores que vão utilizar o módulo, ele é considerado uma caixa-preta, no sentido que não se sabe como ele funciona internamente. O importante é que ele forneça o resultado que se espera dele. Porém, a programação modular também apresenta seus problemas. O primeiro e principal problema é o fato que módulos não eram naturalmente extensíveis. Isso significava que para fazer alterações em módulo, era necessário entrar no código-fonte e diretamente realizar as modificações. E em muitas situações, se via a necessidade de criar novas funcionalidades dos programas a partir de módulos já existentes. 14
  • 15. Programação II 3.4. O Paradigma Orientado a Objetos O termo “programação orientada a objetos” foi criado por Alan Kay (imagem ao lado), autor da linguagem Smalltalk. Sua proposta visa aproximar a maneira como construímos os programas de computador do mundo real. O mundo real é composto por entidades que interagem, que trocam serviços entre si para realizar suas tarefas. Na proposta de orientação a objetos, estas entidades são chamadas objetos. Objetos podem representar tanto entidades concretas (como uma pessoa ou um livro) quanto entidades abstratas (como uma transação bancária ou uma sessão de um usuário ao acessar um site). Para identificar objetos são empregadas técnicas que os próprios seres humanos utilizam para organizar seus pensamentos, como classificação de elementos, diferenciação entre parte e todo, troca de mensagens, dentre outros. Alan Kay utilizou uma analogia com um sistema molecular, batizada então de “analogia biológica”. Nesta proposta, ele se questionou: “como seria um sistema de computador que se organizasse como um ser vivo?”. Sua proposta estabelecia que: » O sistema seria organizado em células, onde cada célula se comportaria como uma unidade autônoma; » Cada “célula” interagiria com outras células através do envio de mensagens para realizar um objetivo comum; Para Kay, objetos do mundo real também se comportam como estas células. A partir de sua analogia biológica, ele estabeleceu os princípios básicos para a orientação a objetos. São estes: 1. Qualquer coisa é um objeto; 2. Objetos realizam tarefas através da requisição de serviços a outros objetos; 3. Cada objeto pertence a uma determinada classe. Uma classe agrupa objetos similares; 4. A classe é um repositório para comportamento associado ao objeto; 5. Classes são organizadas em hierarquias. 3.4.1. Estabelecendo um exemplo Para melhorar sua compreensão, vamos utilizar um exemplo prático. Imagine a situação em que um cliente chamado Ian deseja comprar uma pizza via um serviço de entrega em domicílio. Ian interage com uma atendente (Maria) e faz sua solicitação. Maria por sua vez interage com Mário, o pizzaiolo, repassando a solicitação de Ian, uma vez que quem sabe fazer a pizza é Mário, afinal ele é o pizzaiolo. Após a pizza ficar pronta, ela é entregue ao Zé, o motoboy, que tem por função entregar a pizza a Ian e receber o pagamento. A Figura 10 ilustra a interação entre estes personagens. 15
  • 16. Programação II Figura 10 – Um exemplo para a orientação a objetos na vida real Embora o exemplo acima ainda possa ser refinado e inserir ainda mais participantes, ele é suficiente para ilustrar os conceitos propostos pelo paradigma orientado a objetos. Primeiramente, cada elemento que participa do processo é considerado um objeto. Cada objeto é uma entidade única no sistema. No caso temos Ian, Maria, Mário e Zé como objetos. Não existem duas “Marias”. Poderiam até existir duas funcionárias com o mesmo nome, mas não seriam a mesma pessoa. Cada objeto tem dados ou propriedades que os identificam. No caso, cada pessoa no processo tem um nome. Cada objeto interage com os demais por meio da solicitação de serviços. No caso, Ian solicita seu pedido através da atendente Maria, que lhe fornece os produtos que ela pode entregar a Ian. De forma semelhante, Maria solicita a Mário a pizza escolhida por Ian, passando informações necessárias para realização deste serviço, como o sabor da pizza e o tipo da borda, como ilustrado na Figura 11. Figura 11 – Solicitação de um serviço através da troca de mensagem entre objetos Seguindo sua análise, cada objeto pertence a uma determinada classe que agrupa objetos similares. No nosso exemplo, a pizzaria não atende apenas ao cliente Ian. Podem existir outras dezenas de clientes que também podem fazer seus pedidos à Pizzaria. Estes clientes possuem características comuns, como um cadastro na loja ou um endereço de 16
  • 17. Programação II entrega. Obviamente, para cada cliente, os valores associados a estas propriedades são, em geral, diferentes. Estes objetos são tratados e agrupados como um tipo único de objeto, uma classe. Neste caso, poderíamos agrupar Ian, Cris e Evandro como objetos da classe Cliente, como ilustrado na Figura 12. Figura 12 – Objetos de uma mesma classe Por fim, classes são organizadas em hierarquias. No nosso exemplo, Maria, Mário e Zé poderiam ser agrupados em uma classe que representem os funcionários da Pizzaria (Figura 13). Estes possuem características comuns como um salário, um horário de trabalho. Porém, estes também poderiam ser classificados como pessoas, com atributos como nome, sexo, dentre outros. Neste caso, a classe Pessoa englobaria tanto funcionários quanto clientes, indicando que existem certas propriedades comuns, como o fato de tanto clientes quanto funcionários possuírem um nome. Figura 13 – Hierarquias de classes de objetos Mas vistos estes conceitos, em que a orientação a objetos pode melhorar a forma como programamos nossas aplicações? Para isso, vamos pegar o exemplo do cálculo de uma folha de pagamento de uma empresa, como ilustrado na Figura 14. Figura 14 – Uma folha de pagamento no modelo estruturado 17
  • 18. Programação II Relembrando: como os dados e funções são separados, calcular o custo total da folha requer que saibamos individualmente todos os dados de cada funcionário, o que acabava por fazer com que a evolução do sistema ficasse bastante complicada. Agora veja como seria uma possível versão utilizando a abordagem orientada a objetos (Figura 15). Figura 15 – Uma folha de pagamento no modelo de objetos Nesta versão, cada funcionário é representado por um objeto. Um objeto atua como um módulo que engloba dados, e também fornece operações que manipulam tais dados. Os dados internos de cada objeto são chamados atributos, enquanto as operações que um objeto fornece são chamados de métodos. No caso, todo objeto que representa um funcionário possui como atributos seu nome, seu cargo, seu salário fixo e uma série de outros atributos que são comuns a qualquer funcionário da empresa. Para se calcular seu salário, cada funcionário oferece um método chamado calculaSalario, que internamente utiliza os dados de cada objeto e fornece o valor de seu salário individual. Para calcular o custo total da folha de pagamento seria então somar os valores obtidos pela chamada de cada método calculaSalario, em cada objeto que representa um funcionário da empresa. A orientação a objetos representa uma nova forma de enxergar e modelar o mundo como um conjunto de objetos inter-relacionados, interagindo por meio da troca de mensagens. A abstração escolhida (objeto) combina estrutura de dados e comportamento funcional, fazendo com que os dados sejam preservados e procedimentos modificados mais facilmente, sem causar impactos tão profundos quanto o paradigma estruturado. A ocorrência de erros ou alterações vão estar associadas a um único módulo ou a um pequeno grupo deles, onde é mais fácil depurar e isolar erros. Esta forma de organizar os programas cria um modelo mais intuitivo e fácil de usar, mas principalmente, aumenta a possibilidade de reuso entre objetos. Objetos podem ser criados a partir de outros objetos. Por exemplo, você poderia criar um objeto que representasse um funcionário diferenciado, como aquele cujo salário fosse baseado em comissões, e não em um salário fixo. Este objeto poderia ser criado através de um mecanismo especial de extensão chamado Herança. Resumidamente, este novo objeto teria as mesmas características de um funcionário comum, mas poderia ter dados a mais, assim como seus métodos poderiam ser modificados, como no caso de seu salário. 3.5. Programação Orientada a Objetos VS Programação Estruturada A forma de organizar um programa usando orientação a objetos é essencialmente diferente do desenvolvimento tradicional de software. Mesmo assim, alguns conceitos do modelo orientado a objetos podem ser equiparados a conceitos do modelo estruturado, 18
  • 19. Programação II como visto na figura a seguir. Figura 16 – Paradigma orientado a objeto VS Paradigma Estruturado A programação orientada a objetos é especialmente útil à medida que os sistemas tornam-se cada vez mais complexos, e por consequência, seus programas ficam cada vez maiores. Grandes programas se beneficiam mais com a modularidade oferecida por objetos. Dividindo o programa em vários módulos independentes (objetos), aumenta-se a flexibilidade e a facilidade para manutenção do programa como um todo. Na programação estruturada, a reusabilidade é limitada a trechos de algoritmos representados por meio de sub-rotinas. Na programação orientada a objeto é possível reutilizar todo um módulo, no caso o objeto, com seus métodos e seus atributos. Em geral, a programação orientada a objetos ainda apresenta como vantagens: código mais lógico, e melhor encapsulado, uma maior facilidade de manutenção e extensão do código, um melhor reaproveitamento de código, dentre outros. Como desvantagens, pode-se afirmar que o aprendizado de uma linguagem orientada a objetos é mais complexo, principalmente para aqueles já familiarizados com o paradigma estruturado. É necessário mudar a forma de pensar na solução de um programa, utilizando conceitos não tão simples quanto do paradigma estruturado. Por fim, dificilmente uma linguagem orientada a objetos conseguirá ter um desempenho em tempo de execução superior a linguagens não orientadas a objetos. Exercícios 1. Com suas palavras conceitue: (a) linguagem de programação e (b) paradigma de programação. 2. Utilizando a Internet, verifique quais são os outros paradigmas de programação existentes além dos apresentados neste capítulo. Explique qual o propósito de pelo menos dois outros paradigmas. 3. Em sua opinião, ainda faz sentido hoje se programar em uma linguagem de baixo nível como Assembly?! Justifique sua resposta. 4. Para muitos pesquisadores, o paradigma orientado a objetos é apenas uma extensão do paradigma estruturado. Você concorda ou discorda desta opinião? Justifique. 5. Utilizando a abordagem de uma programação estruturada, resolva o seguinte problema. É necessário descobrir o atleta que mais marcou gols em um campeonato de futebol. Descreva (em português ou em linguagem de programação que você conheça) como seria solução deste problema. 6. Utilizando o mesmo problema da questão anterior, como seria a solução utilizando 19
  • 20. Programação II objetos. Minibiografia Edsger Wybe Dijkstra (11 de Maio de 1930 — 6 de Agosto de 2002) foi um pesquisador holandês mundialmente conhecido por suas contribuições nas áreas de desenvolvimento de algoritmos e programas de linguagens de programação. Foi o precursor da ideia contrária ao uso de comandos “GOTO” em linguagens de programação, um recurso muito utilizado na sua época. Em seu artigo “A Case against the GO TO Statement”, Dijkstra alertou para vários erros decorrentes do uso da declaração GOTO. Uma transcrição deste artigo pode ser visto na URL: http://www.cs.utexas. edu/~EWD/transcriptions/EWD02xx/EWD215.html. Suas pesquisas impulsionaram o surgimento da programação estruturada.Em 1972, recebeu o Prêmio Turing por suas contribuições com o ALGOL e no campo de linguagens de programação. Vamos Revisar? Você estudou, neste capítulo, como as linguagens de programação evoluíram ao longo dos anos no intuito de facilitar a vida dos programadores das aplicações modernas. Esta evolução foi motivada principalmente pela crescente complexidade dos programas. Com isso, as linguagens têm focado principalmente em criar abstrações que melhorem a compreensão e manutenção destes programas. Você também viu que é possível classificar as linguagens em grupos que seguem o mesmo conjunto de ideias sobre a estruturação e execução de um programa, os chamados paradigmas de programação. Desde o paradigma imperativo até o paradigma estruturado, vários foram os avanços na estruturação dos programas, como a reutilização através de sub-rotinas até o uso de módulos autocontidos que protegem seus dados de acesso indevido. Apesar destas evoluções, havia muito o que evoluir, principalmente no que diz respeito ao reuso dos programas. Para isso, uma nova abordagem de programar foi proposta: a orientação a objetos. Neste novo paradigma, programas se aproximam mais do mundo, através de objetos que interagem para a realização de uma tarefa. No próximo capítulo, você verá com mais detalhes os principais conceitos deste novo paradigma. 20
  • 21. Programação II Capítulo 2 O que vamos estudar neste capítulo? Neste capítulo, vamos estudar os seguintes temas: » Conceitos fundamentais do paradigma orientado a objetos, como: › Classes, Objetos, Atributos e Métodos. › Abstração. › Encapsulamento. › Polimorfismo. › Herança. Metas Após o estudo deste capítulo, esperamos que você consiga: » Descrever os principais conceitos utilizados no paradigma orientado a objetos. 21
  • 22. Programação II Capítulo 2 – Orientação a Objetos: conceitos principais Vamos conversar sobre o assunto? No capítulo anterior, você viu que ao longo dos anos a programação buscou uma constante evolução no intuito de facilitar a vida dos programadores. O progresso na organização dos programas evoluiu. Porém, os sistemas também ficaram cada vez mais complexos. Em particular, os paradigmas de programação até então falhavam principalmente em relação à reutilização de código. Para enfrentar este problema, um novo paradigma surgiu: a orientação a objetos. Vamos abordar neste capítulo os principais conceitos relacionados a esta nova forma de organizar seus programas. Este capítulo é fundamental para seu bom progresso no curso. Então, vamos aprender? 1. Introdução Como vimos no capítulo anterior, a programação orientada a objetos surgiu como uma nova abordagem para tratar a inerente complexidade dos novos sistemas. A programação orientada ao objeto (object-oriented programming) pode ser considerada como uma extensão quase natural da programação modular. Apesar de seus conceitos já terem sido estabelecidos desde a década de 70, apenas em meados da década de 90 que este paradigma começou a ganhar maior destaque na comunidade de desenvolvimento de sistemas. Seu uso enfatizou uma ideia que até então passava despercebida: a aproximação com o mundo real. Na programação orientada a objetos temos a necessidade de buscar as entidades de um domínio, onde através da qual um indivíduo observa a realidade (domínio) e procura capturar sua estrutura (abstrair entidades, ações, relacionamentos) com elementos que forem considerados relevantes para a descrição desse domínio. Com as entidades de domínio identificadas, podemos utilizar as técnicas de abstração para a composição das classes abstratas, construindo desta maneira um sistema facilmente reutilizável nas suas estruturas internas. A abordagem OO (orientada a objetos) enfatiza duas características: (i) reutilização de código e (ii) modularidade. Nisto, OO é imbatível quando comparada com as metodologias antigas. Em termos de modelo computacional podemos dizer que enquanto as metodologias tradicionais utilizam o conceito de um processador, uma memória e dispositivos de I/O para processar, armazenar e exibir as informações. A orientação a objetos emprega um conceito mais real, mais concreto: o de Objeto. Porém, além de objetos, existe uma série de outros conceitos que são importantes para a compreensão do paradigma OO, representados na Figura 17. São eles: encapsulamento, polimorfismo, herança, composição e abstração. 22
  • 23. Programação II Figura 17 – Os pilares do paradigma orientado a objetos Vamos dar uma olhada agora como cada um destes conceitos contribui no paradigma OO. 2. Abstração Abstração é considerada a habilidade de modelar características do mundo real do problema que o programador esteja tentando resolver. Ao mesmo tempo, para melhor lidar com a modelagem de problemas complexos, este processo mental indica que se deve ignorar detalhes não relevantes e focar nas características essenciais dos elementos modelados. Com isso, uma realidade complexa pode ser representada em um modelo simplificado, como os objetos no paradigma OO. A abstração na descrição de objetos depende do ponto de vista e objetivo de quem faz a descrição. Grady Booch, um atuante e renomado pesquisador na comunidade científica, ilustra esta observação na sua frase: “Uma abstração depende mais do observador do que do objeto observado”. Por exemplo, a visão de um apartamento por um engenheiro civil tende a ser diferente da de um decorador de ambientes. O primeiro deve se preocupar mais com os aspectos relacionados ao posicionamento de vigas de sustentação, colunas, dentre outros. Já um arquiteto se preocuparia mais em como otimizar o espaço, maximizar a circulação de ar, do melhor local para colocar mesas e cadeiras. Estas diferentes visões ocorrem pelo diferente interesse que os dois profissionais tem sobre a mesma entidade observada: o apartamento. O mesmo vale para a programação, pois só devemos representar nos sistemas que vamos criar, aquelas características que nos interessam dos objetos reais. Como exemplo, ao modelarmos um objeto avião no contexto de um sistema de venda de passagens aéreas, não vai nos interessar a característica do número de turbinas do avião, mas sim, seu número de assentos disponível. Existe uma série de princípios que são utilizados por nós, humanos, para realizar abstrações em nosso cotidiano. Vamos ver como alguns destes princípios e como eles se aplicam no paradigma OO. 2.1. Classificação/Instanciação Classificação é um mecanismo de abstração através do qual o ser humano percebe a existência de um conjunto de fenômenos da realidade (elementos, interações) com algumas características em comum e atribui um nome (conceito) a esse conjunto (classe) de fenômenos. Já a instanciação é o processo inverso à classificação. Na orientação a objetos, este princípio é utilizado para a identificação de classes e objetos. As duas ações possíveis são: » Classificar significa agrupar objetos com base em estruturas e comportamentos semelhantes; 23
  • 24. Programação II » Instanciar objetos significa gerar novos exemplares a partir de uma descrição abstrata de um objeto genérico. Vejamos o exemplo na Figura 18, que ilustra estes processos no contexto de dois estudantes, João e Maria. Ambos são indivíduos, com seus dados particulares, como seus nomes. Porém, ambos podem ser agrupados no conjunto de indivíduos que representam os estudantes. Figura 18 – Classificação/Instanciação de objetos A “semântica” ou o significado do mecanismo de classificação equivale a um mecanismo de pertinência. Neste mecanismo, o fato de um objeto pertencer a uma determinada classe pode ser melhor caracterizado se ocorrer uma relação do tipo “é um / é uma”. Por exemplo, “Maria é uma estudante”. A partir desta abstração, pode-se então melhor entender os conceitos de objetos e classes, atributos e métodos. Objetos representam entidades do mundo real, quer sejam estas concretas ou abstratas, sobre as quais são armazenados dados e temos operações para manipulá-los. Objetos também se caracterizam por ter uma identidade única, um comportamento e um estado. A identificação de objeto deve ser única, uniforme e independente do conteúdo do objeto. Isso implica que podem haver objetos com características semelhantes (como dois martelos azuis ou dois funcionários com o mesmo nome), mas que são distintos. Uma classe é abstração das características mais importantes de um grupo de objetos semelhantes. Cada classe descreve um conjunto (possivelmente infinito) de objetos individuais. A partir de uma classe podem ser gerados diferentes objetos e por isso, cada objeto é dito ser uma instância de uma classe. Assim, cada instância de uma classe tem seus próprios valores para cada dado que o caracteriza, mas também podem compartilhar dados e comportamento com as outras instâncias da classe. Implicitamente, cada objeto contém uma referência para sua própria classe -- em outras palavras, ele sabe o que ele é. Existe hoje uma representação bastante difundida para representar graficamente classes em um modelo orientado a objetos. Esta notação é definida por uma linguagem visual chamada UML (do inglês, Unified Modeling Language). UML é utilizada para representação de muitas etapas durante a análise de um sistema. Ela é formada por vários diagramas. Um deles é o diagrama de classes, em que classes são representadas graficamente. Para facilitar nossa explicação sobre os conceitos OO, utilizaremos a notação UML para descrever as classes nesta disciplina. Em UML, uma classe é representada como descrito na figura a seguir. 24
  • 25. Programação II Figura 19 – Notação UML para Classes Nesta notação, há uma caixa retangular composta de três partes. A primeira parte (localizada no topo do retângulo) define o nome da classe. Esta é única parte que deve existir na notação UML para representar uma classe. A parte intermediária diz qual é a estrutura da classe. Enquanto a parte inferior informa qual é o seu comportamento, através das ações que objetos desta classe podem realizar. Para melhor exemplificar, a classe Estudante tem como estrutura interna o nome do estudante e o curso ao qual ele está vinculado. Como ações, é possível pedir para um objeto imprimir seu nome. Cada objeto possui um conjunto de características ou informações que os caracteriza, chamadas então de atributos. O conjunto de atributos também é chamado de estrutura da classe. Por exemplo, a classe Estudante pode conter como sua estrutura informações como o nome, sexo, data de nascimento, colégio ou faculdade, dentre outros. Os atributos possuem valores, funcionando como variáveis. Por exemplo, o atributo nome para um dos objetos da Figura 19 deve guardar o valor “João”. O conjunto de valores dos atributos de um determinado objeto é chamado de estado. Como visto na Figura 19, atributos (se existirem) são representados na parte intermediária de uma classe em UML. O comportamento de um objeto é definido através de seus métodos. Métodos definem as habilidades dos objetos. Em outras palavras, as ações que um objeto de uma classe pode realizar. É comum serem chamados também de comportamento de uma classe de objetos. Na maioria das vezes, métodos utilizam os atributos da classe como “matéria- prima” para realizar suas ações, além de também poderem receber parâmetros, como em um procedimento tradicional. Uma classe pode ter qualquer número de métodos, inclusive nenhum. Por exemplo, para uma classe carro, poderiam ser definidas ações como andar, frear, ligar o motor, dentre outras. Como visto na Figura 19, métodos (se existirem) são representados na parte inferior de uma classe em UML. Métodos são definidos nas classes, porém sua execução só ocorre quando o método é invocado através do objeto. Por exemplo, pode haver uma classe que represente um automóvel e dois objetos que representem dois modelos diferentes: um Fusca e uma Ferrari. A classe define um método, que faz com que a velocidade do automóvel seja reduzida. A utilização de um método frear() deve afetar apenas um objeto em particular. Todos os carros podem frear, mas a ação em um objeto afeta apenas o objeto em questão. Apesar da independência de cada objeto, para que um sistema funcione é necessário que os objetos interajam. A interação entre objetos ocorre através da troca de mensagens. Uma mensagem representa o ato de um objeto de uma classe chamar algum método que outro objeto possua, fazendo com que este comportamento seja executado. É comum esta ação ser chamada de ativação ou invocação de um método. Em analogia com a programação estruturada, uma mensagem pode ser vista como uma chamada a procedimento, inclusive com o retorno de um resultado a partir da execução deste método, como ilustrado na Figura 20. 25
  • 26. Programação II Figura 20 – Ilustração do envio de uma mensagem para um objeto Para um objeto invocar um método em outro objeto é necessário que obtenha uma referencia ao objeto-alvo. Como cada objeto precisa ser identificado de forma unívoca (ou seja, de forma exclusiva), faz-se então necessário definir um identificador para cada objeto. Tome como exemplo a Figura 21. A classe Estudante define as características gerais de um aluno. O método imprimirNome() é definido para apresentar tanto o nome do aluno, quanto seu curso. Figura 21 – Referências para objetos Existem dois objetos que representam dois alunos distintos. Para isso, cada objeto tem um identificador único. Para o aluno cujo nome é Fernando, o identificador do objeto é aluno1, enquanto para o outro aluno, aluno2. Para se mandar uma mensagem para um dos objetos utiliza-se a chamada “sintaxe do ponto” (dot syntax). Esta sintaxe indica que o acesso a um atributo ou método de um objeto deve ser feita utilizando a forma “objeto.método” ou “objeto.atributo”. No nosso exemplo, para chamar o método imprimirNome no objeto aluno1, deve ser utilizada a notação aluno1.imprimirNome(). Dessa forma, representa-se a ativação de uma mensagem neste objeto. 2.2. Agregação/Composição A ideia de agregação ou composição estabelece a criação de novas classes de objetos a partir da junção de classes já existentes. Essa ideia de composição é muito comum para se representar relações do tipo todo-parte, como no caso de uma turma ser composta por instâncias de outras classes, como um professor, um conjunto de alunos, dentre outros. Da mesma forma que a classificação/instanciação são processos inversos, para a composição de classes são definidas duas operações diferentes: 26
  • 27. Programação II » Operação de Agregação: Quando unimos um conjunto de objetos para formarmos um novo objeto; » Operação de Decomposição: Quando, analisando um objeto, isolamos cada um de seus componentes. Veja o seguinte exemplo: Figura 22 – Agregação/Decomposição Neste exemplo, a classe Automóvel pode ser decomposta nas classes Placa e Motor. Este processo, chamado de decomposição, realiza uma análise sobre a classe Automóvel e aplica um refinamento. Refinar significa deixar ainda mais claro a estrutura de um determinado conceito. O processo inverso faz uma síntese de conceitos já existentes para criar um novo conceito. Há uma notação especial em UML para representar agregação, como ilustrado e exemplificado na Figura 23. Um losango vazado é anexado à extremidade de um caminho de associação ao lado do agregado (o todo) para indicar agregação. Figura 23 – Notação UML para agregação; Tipos de Agregação Há uma distinção entre dois tipos de agregação: a agregação compartilhada e a composição. No primeiro tipo, representado pela ideia de uma disciplina que contem um 27
  • 28. Programação II professor e uma sala vinculada, objetos contidos podem existir sem serem parte do objeto que os contém. Em outras palavras, um professor continuará a existir, mesmo que não haja o conceito Disciplina. No caso da composição, objetos contidos não fazem sentido fora do contexto do objeto que os contém. No exemplo apresentado, um pedido contem itens e um Cliente vinculado. Se você destruir o pedido, os itens são destruídos junto, pois eles não tem sentido fora do pedido. Neste caso, o losango anexado à extremidade da classe agregadora deve ser preenchido, e não vazado. 2.3. Associações Simples As entidades envolvidas apresentam existências independentes, mas existe uma ligação entre elas. A agregação não é única forma de relacionamento entre objetos e classes. Classes e objetos podem formar associações, que consistem na descrição genérica de uma ou mais ligações entre as classes, permitindo que objetos de uma classe utilizem recursos de outros objetos. Ao se estabelecer associações entre classes, em geral se estabelece o significado de uma classe “usar” ou “possuir” outra. Para representar associações entre classes, UML utiliza uma linha unindo as duas classes. Alguns exemplos de associações são descritas abaixo. Figura 24 – Associações entre classes Nos exemplos acima, temos que um cliente está vinculado a um produto, e vice-versa. Uma conta possui um histórico de transações. Um hóspede está vinculado à um quarto. Associações podem ainda ser refinadas inserindo a multiplicidade nos relacionamentos entre classes. Por exemplo, um único cliente pode estar vinculado a zero ou mais (sem limites) pedidos. Um velocista pode participar de zero ou mais corridas, e uma corrida deve ter no mínimo dois e no máximo seis velocistas. 2.4. Encapsulamento Um dos aspectos mais positivos da programação modular foi a ideia de encapsulamento de informações. A programação orientada a objetos preserva este conceito. Encapsular dados em OO consiste em separar os aspectos externos de um objeto, os quais são acessíveis a outros objetos, dos detalhes internos de implementação do objeto, os quais permanecem escondidos dos outros objetos. O uso de encapsulamento evita que objetos possuam grandes dependências entre si, de modo que uma simples mudança em um objeto possa trazer grandes efeitos colaterais e problemas para outros objetos. Como vimos no capítulo I, o conceito de encapsulamento não é exclusivo da abordagem de orientação a objetos. Entretanto, a habilidade de se combinar estrutura de dados e comportamento em uma única entidade torna o encapsulamento mais elegante e mais poderoso do que em linguagens convencionais que separam estruturas de dados e comportamento. 28
  • 29. Programação II No paradigma OO, o encapsulamento institui conceitos e regras que ajudam a promover a modularidade entre objetos. Para isso, o acesso a componentes de um objeto é controlado e, especialmente, os atributos de um objeto só devem ser modificados pelos métodos do próprio objeto. Veja como isso ajuda a proteger um programa. Imagine a classe Conta que representa uma conta corrente, cujos atributos são seu número e seu saldo na Figura 25. Figura 25 – O benefício do encapsulamento De acordo com projeto, o saldo de uma conta não pode ser menor que zero. Mas da forma como até agora conhecemos classes, o acesso a atributos e métodos é liberado. Logo, qualquer objeto poderia ter o atributo saldo acessado diretamente, e modificado para um valor inválido, como representado no exemplo. Para sanar este problema, linguagens orientadas a objetos oferecem mecanismo que modificam a visibilidade (escopo) de atributos e métodos. É possível então estabelecer que todos os atributos de uma classe só possam ser acessados de métodos definidos dentro da própria classe. É dito então que o escopo deste método é privado à sua classe. No nosso exemplo, a modificação do saldo de uma conta só poderá ser feita através do método debitar(valor) que internamente estabelece regras que não permitem que o saldo da conta fique negativo. A ideia do encapsulamento faz também com que o sistema não dependa das implementações internas das classes, mas sim de suas interfaces. A interface de um objeto é representada pelo conjunto de todos os métodos que este objeto oferece a outros objetos. A interface de um objeto é que é externamente visível, e que protege dados internos, além de outras operações que não devem ser disponibilizadas ao mundo externo. Imagine uma classe que represente o conceito de uma coleção de pessoas, e que forneça métodos para manipular esta coleção, como inserir uma pessoa, consultar uma pessoa pelo nome, etc. Internamente, esta classe poderia utilizar diferentes estruturas para guardar a coleção de pessoas, como um vetor, uma lista dinâmica ou mesmo um banco de dados. Porém, para quem vai utilizar algum objeto desta classe, isso não importa. O que importa é que exista um método para inserir, outro para consultar, e assim por diante. Desta forma, alterações dentro da classe não afetarão o restante do sistema. Por exemplo, pode- se trocar a implementação interna da classe, mudando de um vetor para o banco de dados. Se a interface for mantida, os objetos que usam não sofreram nenhum impacto, o que torna a manutenção mais fácil. Por estes motivos, na orientação a objetos é muita utilizada a expressão “programar 29
  • 30. Programação II para a interface”. Esta expressão indica a ideia que a interface de um objeto representa um contrato entre uma classe de objetos. Enquanto o contrato for mantido, objetos que dependam dos métodos de uma classe não serão prejudicados. 2.5. Generalização/Especialização (Herança) Generalização e especialização são abstrações que permitem o reuso de objetos através da criação de classes de objetos a partir de outras classes. No caso, a especialização é o mecanismo pelo qual pode-se definir uma nova classe de objetos a partir de uma classe já existente. Esta nova classe poderá aproveitar o comportamento e possíveis atributos da classe estendida. A classe sendo refinada é chamada de superclasse ou classe base, enquanto que a versão refinada da classe é chamada uma subclasse ou classe derivada. A generalização é o inverso da especialização. A Figura 26 ilustra esta relação: Figura 26 – Generalização/Especialização, a base para a Herança entre classes Neste exemplo, a superclasse Estudante é refinada em dois tipos mais específicos, os de graduação e os de pós-graduação. Diz-se que cada classe derivada herda as características de sua classe base. Por conta disso é mais comum essa abstração serem tratadas em linguagens de programação orientadas a objetos como Herança. No nosso exemplo, a classe Estudante poderia ter como atributos: nome ou instituição vinculada, estes também são atributos de estudantes de graduação ou pós-graduação. Cada classe derivada não apenas herda as características de seu ancestral como também pode acrescentar seus atributos e operações específicos, como o curso para o Estudante de Graduação. Em UML, a notação para generalização é representada por uma associação entre superclasse e subclasses, onde um triângulo é posto na extremidade próxima à superclasse (Figura 27). 30
  • 31. Programação II Figura 27 – Representação UML para Herança; Exemplo para uma hierarquia de classes É importante salientar que a herança não vale apenas para dados, mas também para métodos. No mesmo exemplo, a classe Estudante define um método imprimeDados. Portanto, as subclasses da classe Estudante também herdam este comportamento. Com isto, embora o método não seja definido na classe EstudanteGraduação ou EstudantePos, qualquer objeto de uma destas duas classes pode ter o método imprimeDados sendo invocado. A correta chamada de métodos ou o acesso a atributos em classes que possuam uma relação de herança ocorre através da busca nas classes que participam da hierarquia. Exemplificando: quando um método é chamado em um objeto de uma classe, a especificação deste método é procurada na classe deste objeto. Se este método não é encontrado, busca-se então na definição de sua superclasse, e assim por diante, pois uma hierarquia de herança pode ser formada por várias classes, recursivamente aplicada a um número arbitrário de níveis. A Figura 28 exemplifica uma relação de herança em mais de um nível. Figura 28 – Múltiplos níveis de herança 31
  • 32. Programação II Neste exemplo, o Estudante de Graduação além do curso, possui também como atributos herdados a matricula (da classe Estudante) e o nome (da classe Pessoa). Uma subclasse pode também sobrepor uma característica de sua superclasse, o que significa que a nova característica local à subclasse irá substituir a característica de sua superclasse. Neste caso, esta ação é chamada de sobreposição. Ainda no exemplo anterior, a classe Estudante sobrepõe o método imprimeDados da classe Pessoa. Em outras palavras, a execução deste método em objetos da classe Estudante obedecerá a esta nova definição. Note que esta alteração também afeta objetos das classes EstudanteGraduação e EstudantePos. Objetos dos tipos Pessoa e Empregado executam a definição original do método. A definição e uso de herança traz consigo também um princípio muito importante para a orientação a objetos que é o princípio da substituição. Este princípio se baseia no fato que, se uma subclasse herda métodos e atributos de sua superclasse, em qualquer lugar de um programa que você possa utilizar uma instância de superclasse, você também deve poder utilizar uma instância de qualquer subclasse desta classe. Embora pareça complicado, imagine um programa que faz uma chamada ao método imprimeDados de um objeto Pessoa, de acordo com a hierarquia de classes da Figura 27. Pelo princípio da substituição, você pode substituir este objeto Pessoa por qualquer outro objeto que seja instância de alguma subclasse de Pessoa, como Estudante, Empregado, EstudantePos ou EstudanteGradução. Como todos eles vão possuir o método imprimeDados, o programa vai continuar a funcionar sem problemas. Este princípio é muito útil para facilitar a extensão de programas. Herança Simples e Herança Múltipla A herança pode ser de dois tipos: Simples e Múltipla. A herança simples é quando uma classe é subclasse de somente uma superclasse, enquanto a herança múltipla ocorre quando uma classe é subclasse de várias superclasses e, consequentemente, herda as características de cada uma delas. Os exemplos que vimos até agora foram todos de herança simples. A Figura 29 apresenta um exemplo de uma herança múltipla. Figura 29 – Exemplo de Herança Múltipla Neste caso, note que a classe VeiculoAnfibio possui duas superclasses, Carro e Barco. Desta forma, ela herda métodos e atributos destas duas classes. Herança múltipla não se limita a apenas duas classes, de acordo com o contexto do mundo que se queira modelar. Porém, a herança múltipla traz um problema: o conflito de atributos ou métodos herdados das superclasses. Em nosso exemplo, note que tanto Carro quanto Barco possuem um método parar. Imagine então o que aconteceria se fosse feita uma chamada ao método parar em um objeto do tipo VeiculoAnfibio. Qual implementação de parar deveria ser chamada? 32
  • 33. Programação II Por conta dessa e de outras questões, a Herança Múltipla não é implementada em todas linguagens de programação, como no caso de Java. Porém, pode ser encontrada em outras linguagens como C++ e SmallTalk. 2.6. Polimorfismo O termo polimorfismo é originário do grego, e etimologicamente quer dizer “muitas formas”. Na orientação a objetos, isso significa que um mesmo tipo de objeto, sob certas condições, pode realizar ações diferentes ao receber uma mesma mensagem. Ou seja, objetos podem ter reações diferentes ao mesmo estímulo (Figura 30). Figura 30 – Polimorfismo: Objetos têm diferentes reações a um mesmo estímulo Polimorfismo permite o envio de uma mesma mensagem a objetos distintos, onde cada objeto responde da maneira mais apropriada para a classe chamadora. No exemplo da Figura 30, a mesma mensagem “desenhar” pode ser enviada a três objetos distintos: o quadrado, o círculo e o triângulo. Os três sabem como tratar esta mensagem, porém cada um realizará ações diferentes. Existem dois tipos principais de polimorfismo: a sobrecarga e a sobreposição. Na sobrecarga, uma mesma classe de objetos possui métodos com o mesmo nome, porém quantidade ou tipo de parâmetros diferentes. No momento da chamada do método, dependendo do parâmetro, um método ou outro será chamado. Por exemplo, a classe Pessoa (Figura 31) possui dois métodos imprimir. O primeiro recebe apenas um parâmetro, enquanto o segundo recebe dois. Figura 31 – Sobrecarga de métodos Já a sobreposição ocorre somente associada à herança. Quando um método definido na superclasse não serve da forma original para a subclasse, ele tem de ser redefinido. Como na redefinição a assinatura deve ser mantida, o novo método sobrepõe o método definido na superclasse. Veja como exemplo a Figura 32. Existem dois tipos de Funcionário: o que recebe um salário fixo (Empregado) e outro cujo salário é calculado de acordo com suas vendas 33
  • 34. Programação II (EmpregadoComissão). O segundo tipo tem as mesmas características do primeiro, portanto convém que se utilize herança para reaproveitar seus dados. Porém, o calculo de seu salário é totalmente diferente. Neste caso, a subclasse modifica (sobrepõe) o comportamento do método que calcula o salário para a classe EmpregadoComissão. Figura 32 – Sobreposição de métodos Neste caso, quando um objeto for do tipo Empregado, o calculo do salário obedecerá a regra definida na superclasse. Mas quando o objeto for do tipo EmpregadoComissão, a regra utilizada é aquela que foi redefinida nesta classe. Em resumo: » O método a ser chamado é aquele pertencente ao objeto o qual a chamada está relacionada; » Caso o objeto não possua este método, a chamada é transferida para a superclasse, e assim por diante até que o método seja encontrado; Porém, ao contrário da sobreposição, métodos sobrepostos na subclasse precisam ter a mesma assinatura de seus equivalentes na superclasse. Em outras palavras, precisam ter o mesmo nome; o mesmo número de parâmetros e o mesmo tipo de parâmetros de entrada e saída. Exercícios 1. No contexto da programação orientada a objetos, o que é um objeto? 2. No contexto da programação orientada a objetos, o que é uma classe? Diga também o que são métodos e variáveis de instância. 3. Indique qual é o principal benefício obtido quando os atributos de uma classe não são visíveis a outras classes? Qual é o nome desta técnica de programação? 4. Explique o que é o relacionamento de herança entre classes. 5. Para você, qual o benefício do polimorfismo no paradigma orientado a objetos? 6. Utilizando orientação a objetos, indique quais seriam as classes, seus atributos, métodos e associações para os seguintes sistemas: a) Uma universidade; b) Um acervo de mídias (CDs e DVDs) c) Um filme. 34
  • 35. Programação II Vamos Revisar? Neste capítulo, você foi apresentado a uma nova forma de organizar os conceitos para criação de programas de computador. A orientação a objetos baseia-se em uma aproximação da forma como os seres humanos organizam e realizam ações no mundo real. Para isso, novas abstrações como classificação, agregação, associação, dentre outras são fundamentais para que os programas sejam organizados de forma a permitir um maior reuso de código e maior flexibilidade de manutenção. Conceitos como classes, objetos, métodos e atributos são fundamentais em linguagens orientadas a objetos, vão fazer parte do dia a dia deste curso. A partir deles, conceitos mais avançados como herança e polimorfismo são gerados, e serão mais detalhados adiante nesta disciplina. Por enquanto, é importante que os conceitos deste capítulo seja amadurecidos em sua cabeça. 35
  • 36. Programação II Capítulo 3 O que vamos estudar neste capítulo? Neste capítulo, vamos estudar os seguintes temas: » Linguagem de Programação Java » Java Software Development Kit – JSDK » O ambiente de programação JCreator Metas Após o estudo deste capítulo, esperamos que você consiga: » Identificar as principais características da Linguagem Java; » Instalar e configurar o Kit de desenvolvimento necessário para compilar e executar seus programas em Java; » Instalar o ambiente de programação JCreator; 36
  • 37. Programação II Capítulo 3 – A Linguagem Java Vamos conversar sobre o assunto? Nos capítulos iniciais deste volume você aprendeu sobre a necessidade de melhorar a forma como organizamos os conceitos em linguagens de programação e como a orientação a objetos busca melhorar o reuso e a manutenção de programas. Bem, até agora, tudo foi bastante teórico. Então chegou a hora de começarmos a ver como na prática isso tudo funciona. Para isto, este capítulo introduz a linguagem de programação orientada a objetos mais popular no mundo: Java. 1. Introdução Você Sabia? A linguagem de programação Java tem origem no início da década de 90, dentro da Sun Microsystems. Na época, uma equipe liderada por Patrick Naughton, Mike Sheridan, e James Gosling tinha como objetivo projetar uma nova linguagem de programação capaz de criar softwares capazes de comunicar diferentes dispositivos entre si. Originalmente, batizou-se esta linguagem de Oak (carvalho, em inglês), em homenagem a um espécie de árvore que os integrantes do projeto avistavam de sua sala. Inicialmente a proposta de interoperabilidade de programas não foi muito bem aceita pelo mercado, o que então fez com os objetivos fossem modificados. Na época, o Você sabia que a linguagem Java tem uso da Internet estava crescendo vertiginosamente. Foi então que a Sun viu nesta expansão esse nome devido a uma oportunidade de usar Oak. A linguagem passaria então a ser voltada para construir um café? aplicações para Web. A linguagem foi rebatizada e passou a se chamar Java, sendo Durante o projeto os apresentada oficialmente em 1995. participantes tomava muito café, e gostavam Desde então, Java foi rapidamente adotada pelo mundo, mais rapidamente que principalmente de qualquer outra linguagem de programação até então. Grandes fornecedores de tecnologia um proveniente da como IBM, Oracle, Netscape, dentre outros, passaram a apoiar Java. ilha de Java. No meio do projeto Green, A linguagem evoluiu muito ao longo dos anos. Hoje, mas que uma linguagem, os projetistas foram avisados que já havia Java pode ser vista como uma plataforma de desenvolvimento e execução de programas uma linguagem com em diversas plataformas. Você encontra programas Java na Web, dos telefones celulares, o nome de oak, que mainframes, cartões inteligentes, dentre outros. Com isso, a linguagem é dividida em 3 inicialmente era o grandes segmentos: escolhido. Com isso, os projetistas resolveram 1. JEE (Java Enterprise Edition): indicado para aplicações coorporativas, com homenagear a ilha que produzia o café tão necessidade gerenciamento de transações, balanceamento de carga, concorrência, apreciado por todos. dentre outros; 2. JSE (Java Standar Editon): é o ambiente de desenvolvimento mais utilizado. Isso porque seu uso é voltado a PCs e servidores, onde há bem mais necessidade de aplicações; 3. JME (Java Micro Edition): é o ambiente de desenvolvimento para dispositivos móveis ou portáteis, como telefones celulares e palmtops. Hoje, estima-se que haja uma comunidade de mais de quatro milhões de 37
  • 38. Programação II programadores Java no mundo. Existem também grupos de usuários Java, chamados JUGs (Java User Groups), que são utilizados para troca de ideias, dúvidas e melhores práticas no uso da tecnologia Java. No Brasil, existem vários, como o DF-JUG (de Brasília) ou CE- JUG(do Ceará). Existem diversos livros publicados sobre a linguagem, além de diversos ambientes de programação e desenvolvimento. 2. Características da Linguagem Durante seu projeto, a linguagem Java teve uma série de requisitos que podem se apontados como fatores de seu sucesso. 1. Java é orientada a objetos: Java foi baseada no modelo de outras linguagens de programação OO, no caso, Simula67 e SmallTalk. Com isso, os conceitos de herança, polimorfismo e encapsulamento são implementados pela linguagem. A sintaxe e seu sistema de tipos é bem parecido com C e C++, o que facilitou a migração de programação de programadores já acostumados com estas linguagens; 2. Java é portável: Este conceito indica que um mesmo programa escrito em Java pode ser executado em diferentes plataformas hardware ou sistema, sem grandes ou nenhuma mudanças. Por conta desta característica, é comum se associar a Java o seguinte jargão: “escreva uma vez, execute em qualquer lugar; 3. Java é segura, confiável e robusta: Ao contrário de suas predecessoras, Java não trabalha com ponteiros. Em outras palavras, um programador Java não tem acesso direto a posições de memória, um dos grandes problemas para quem trabalha com linguagens como C ou C++. Java possui um mecanismo de tratamento de exceções em que os erros que possam vir a ocorrer durante operações efetuadas são tratadas paralelamente em outro trecho de código do sistema. Um erro que durante a execução do programa poderá ser capturado sem imprevistos como, por exemplo, acessos inválidos de memória do sistema operacional, ou do gerenciador de arquivos, que podem acarretar problemas como o travamento, desligamento do computador e perda de arquivos significativos; 4. Java promove reuso e facilita a manutenabilidade: Java possibilita a criação de componentes reutilizáveis, ou seja, uma vez criadas funcionalidades para os mesmos, estes poderão ser reutilizáveis posteriormente. Com isso é proporcionado um baixo custo de produção e manutenção de códigos gerados com os demais sistemas que venham a ser desenvolvidos; 5. Java é distribuída: Java possui a capacidade de compartilhamento de informações possibilitando a distribuição de tal forma que haja processamento em máquinas distintas. Possui integração com o protocolo TCP/IP que facilita a programação para acessos remotos, utilizando protocolos como: HTTP e FTP; 6. Java permite a carga dinâmica de aplicações: Java oferece o recurso de que aplicações chamadas applets possam ser carregadas remotamente e executadas no contexto de um browser, ao ler uma página na Web. Ao fazer isso, Java introduziu a interatividade na Web, permitindo que aplicações pudessem ser descarregadas e utilizadas automaticamente por usuários, sem necessidade de instalação, ou atualizações de versões. Ao mesmo tempo, applets possuem um criterioso modelo de segurança que previne o acesso de aplicações remotas a possíveis ações danosas no computador do usuário que rode um applet; 7. Java é livre e gratuita: Você não paga nada para criar um programa em Java. O software para execução e construção de programas é disponibilizado gratuitamente 38
  • 39. Programação II na Internet. Além disso, existem vários ambientes gratuitos para facilitar a construção e depuração de programas Java. 3. Máquina Virtual Java: o alcance de portabilidade Uma das características mais importantes da linguagem Java é a portabilidade. Para isto, Java promove o conceito que nada na linguagem deve ser específico de uma plataforma específica. O que na realidade Java faz, é criar a ideia de um computador abstrato sobre o qual o programa deve ser executado. Esse computador abstrato é chamado de máquina virtual Java (JVM). Na realidade, a máquina virtual Java é uma especificação fornecida a início pela Sun, e seu funcionamento une a ideia de compilação e interpretação de programas. Vamos ver como isso funciona. Para criar um programa Java precisamos criar sua especificação através da sintaxe da linguagem. Como em praticamente toda linguagem de programação isso é feito através da edição de um arquivo texto. A partir de um programa escrito corretamente, a etapa que segue é a compilação do programa para geração de sua versão executável. Aqui vem uma grande diferença. Em vez de gerar um arquivo executável que é voltado para um computador ou sistema operacional específico, Java gera uma versão intermediária do programa, o bytecode. O bytecode é um arquivo neutro e independente de plataforma. Ele representa o programa executável e livre de erros, como uma linguagem de máquina destinada a um processador virtual especificado pela máquina virtual Java. Desta forma, qualquer implementação de uma máquina virtual Java deve ser capaz de executar este programa. O que de fato acontece, pois hoje existem implementações da máquina virtual Java para as mais diversas plataformas, como Windows, Linux, MacOS, dentre outros (Figura 33). Figura 33 – O processo de compilação e execução de um programa Java A JVM utiliza o mecanismo de interpretação para executar os bytecodes que correspondem ao programa originalmente escrito pelo programador. O uso de uma máquina virtual acarreta em um tempo a mais na execução do programa, o que indica que programas escritos em Java tendem a ser mais lentos que programas equivalentes escritos em C ou C++. Porém, a facilidade na migração de um sistema entre diferentes plataformas é um requisito cada vez mais importante na construção das aplicações modernas. Ou seja, é um benefício que se paga. Além disso, as atuais implementações de JVM fazem uma série de otimizações que diminuem a diferença em relação à execução de um programa Java e programas compilados diretamente para uma plataforma específica. 39