Baixe o app para aproveitar ainda mais
Prévia do material em texto
Professor Me. Ricardo Bortolo Vieira ● Graduação em Ciência da Computação pela Universidade Estadual de Maringá (2003). ● Especialização de Engenharia de Software pela Universidade Estadual de Londrina (2007). ● MBA em Gestão em Saúde Suplementar pela São Marcos (2009). ● Especialização de Gerência de Projetos pela Fundação Getúlio Vargas (2011). ● Mestre em Desenvolvimento de Tecnologias pelo Instituto LACTEC.(2017) ● Doutorando em Informática para PUCPR . ● Gerente de Desenvolvimento de software e profissional do mercado de TI a mais de 12 anos. ● Professor de nível superior da Faculdade Cidade Verde de Maringá (FCV), Universidade Federal do Paraná (UFPR), Faculdade de Engenharia e Inovação Tecnológica (FEITEP), Fundação Getúlio Vargas (FGV) e Pontifícia Universidade Católica (PUC). ● Experiência na área de Ciência da Computação, com ênfase em Sistemas de Computação e Automação e Robótica, além de experiência em Administração com ênfase em Gerenciamento de Projetos. ● Lattes: http://lattes.cnpq.br/5731213234468142 AUTOR http://lattes.cnpq.br/5731213234468142 Seja muito bem-vindo(a)! Olá prezad@ alun@, este é o livro Programação Orientada a Objetos, sou o professor Ricardo Vieira, autor deste material e o assunto que abordarei no decorrer do nosso estudo poderá auxiliá-lo em sua carreira, ou abrir portas para o mundo dos negócios, mostrando-lhe como é bom trabalhar com programação. Com o passar do tempo, as ferra- mentas para desenvolvimento foram tornando-se mais simples, rápidas e robustas. Meu objetivo, por meio deste livro, é ensiná-lo como programar usando o paradigma Orientado a Objetos, e apresentar algumas técnicas que podem auxiliá-lo neste processo. Além disso, pretendo deixar claro que o uso correto desse paradigma poderá ajudá-lo a alcançar os objetivos estratégicos de sua empresa ou auxiliá-lo a colocar em prática uma nova ideia. Este livro está organizado em quatro unidades, além da introdução e conclusão. Cada uma delas correspondendo a uma das partes importante na programação orientada a objetos. Na primeira unidade você irá estudar o histórico e conceitos desse paradigma que nos permite programar de forma mais próxima do nosso pensamento. Já na unidade II você poderá constatar que a Linguagem de Modelagem Unificada (UML), padroniza o processo de diagramação da estrutura de um software. Independente, tanto da linguagem de programação, quanto de processos de desenvolvimentos, ela é mui- to usada na implementação de um sistema. O diagrama de classe é uma representação da estrutura e relações das classes que servem de modelo para o objeto e será este diagrama que iremos nos aprofundar. Depois, na unidade III, falaremos sobre o encapsulamento, aprendendo a esconder a forma como algo foi feito. Uma vantagem deste princípio é que as mudanças se tornam transparentes, ou seja, quem usa algum processamento não será afetado quando seu comportamento interno mudar. Na unidade IV, vamos entender melhor sobre as bibliotecas de coleções genéricas, ou seja, tratando sobre estruturas abstratas de dados, falaremos também sobre captura e tratamento de erros e exceções e concluiremos apresentando classes provedoras de acesso a banco de dados e o famoso desenvolvimento em camadas. Agora, mãos à obra! Tenha uma boa e agradável leitura! APRESENTAÇÃO DO MATERIAL SUMÁRIO UNIDADE I ...................................................................................................... 5 Histórico e Conceitos Básicos UNIDADE II ................................................................................................... 38 UML e a Organização das Informações UNIDADE III .................................................................................................. 64 Classes, Objetos e Interfaces UNIDADE IV .................................................................................................. 90 Bibliotecas, Classes Especializadas e Desenvolvimento em Camadas 5 Plano de Estudo: 1. Paradigma da programação orientada a objetos 2. Falando sério sobre classes 3. Estrutura de uma classe 4. Modificadores de acesso de classe e membros 5. Considerações finais Objetivos de Aprendizagem: ● Conceituar e contextualizar a Programação Orientada a Objetos. ● Fornecer o conceito e uso de Classes. ● Demonstrar as diferentes partes que compõem uma Classe. ● Definir as aplicações de instanciação por meio de Classes. UNIDADE I Histórico e Conceitos Básicos Professor Mestre Ricardo Vieira 6UNIDADE I Histórico e Conceitos Básicos INTRODUÇÃO Esta unidade inicia os estudos sobre Orientação a Objetos (OO), tratando de temas como Histórico, conceitos iniciais e classes. Embora o assunto seja relativamente novo, tem sido estudado por muitas pesquisadores gerando uma base de conhecimento sólida a qual iremos tratar ao longo deste livro. Cada vez mais empresas estão considerando a Orientação a Objetos como sendo obrigatória para a sobrevivência da empresa. As organizações que eram resistentes a aplicação das boas práticas de programação OO são agora defensoras. Educadores de gestão tradicional, que tratavam com resistência sobre essa técnica, agora são partidários. A Orientação a Objetos chegou para ficar. Colégios e universidades estão agora oferecendo em seus cursos de graduações e de pós-graduação várias disciplinas sobre o assunto. Portanto, não fique fora dessa! Vamos entrar neste novo universo de jargões, con- ceitos, processos e padrões. E iniciando os trabalhos, vamos estudar o histórico do OO que trará fatos interessantes sobre esta área. 7UNIDADE I Histórico e Conceitos Básicos 1. PARADIGMA DA PROGRAMAÇÃO ORIENTADA A OBJETOS 1.1. Introdução de Conceitos e Aplicações Nos primórdios da computação, na década de 1950, quando os computadores eram máquinas gigantescas com pouca capacidade de processamento e armazenamento baixo, mas já exercendo a sua principal função de automatizar nosso dia a dia. Para que os computadores daquela época pudessem executar suas tarefas era necessário a inter- venção humana em muitas etapas (e ainda hoje existe essa necessidade). Porém, neste período o único paradigma de programação existente era o sequencial ou mais conhecido como procedural. A Orientação a Objetos (OO) surge de um trabalho acadêmico genial de Keith Tocher (1967) que formaliza a teoria da simulação no artigo intitulado The Art of Simulation. Não vamos nos prolongar demais nesta teoria, o importante é dizer que ela foi baseada em modelos matemática e subdivida em três categorias: Discrete Events Simulation, Con- tinuous Simulation e Monte Carlo Simulation. A categoria Discrete Events Simulation trabalha com mudanças de estado, rela- cionamentos e trocas de informações. Dessa forma, é fácil perceber que onde nossa OO surgiu. O que é um ponto de vista Orientado a Objetos? Por que um método é considerado 8UNIDADE I Histórico e Conceitos Básicos orientado a objetos? O que é um objeto? À medida que os conceitos orientados a objeto ganharam ampla aceitação durante as décadas de 1980 e 1990, surgiram muitas opiniões diferentes sobre as respostas corretas a essas perguntas, mas atualmente há uma visão coerente dos conceitos orientados a objeto. Esta introdução lhe proporcionará uma rápida visão do tópico e apresentará os conceitos básicos e a terminologia. (Pressman 2011). A principal característica do Paradigma Orientado a Objetos (POO) é uma maior e melhor expressividade das necessidades do nosso dia a dia. Possibilitando criar uma unidade de código mais próxima da forma como pensamos e agimos, assim facilitando o processo de transformação das necessidades diárias para uma linguagem orientada a objeto. Assim, Orientação a Objetos é um paradigma de análise, projeto e programação de sistemas de softwares baseadona composição e interação entre diversas unidades de software chamadas de objetos. Dá-se o nome de Programação Orientado a Objeto ao processo que utiliza uma linguagem orientada a objeto. A sigla POO termina se fundindo entre a programação e o paradigma. A utilização de uma linguagem orientada a objeto somente, em alguns casos, não garante que se está programando efetivamente orientado a objeto. Isso ocorre devido aos “vícios estruturados” dos novos programadores ou até mesmo de programadores experientes, mas que acabam cometendo o mesmo erro no final, que é programar estruturado em uma linguagem Orientado a Objetos. Mesmo isso parecendo muito estranho, este é um fato que ocorre com muita frequência, infelizmente entre muitos programadores deste paradigma. É importante prover um embasamento sobre os fundamentos da Orientação a Objeto. Todo os conceitos tem como finalidade possibilitar e facilitar a aplicação destes conceitos. O uso correto destes conceitos eleva e facilita o processo de programação. O ponto de partida para a compreensão de OO é compreender o que é objeto e seus aspectos envolvidos em sua criação e sua manipulação. No mercado atual de softwares, grandes linguagens de programação como Java, ASP.NET, CSharp, C++, Python são orientados a objeto, assim você consegue perceber a 9UNIDADE I Histórico e Conceitos Básicos importância de estudar e absorver os conceitos de OO. Neste livro iremos discutir o assunto de OO usando como base a linguagem JAVA. 1.1.1. Abstração Da mesma maneira que em nosso cotidiano, nós abstraímos de certas dificuldades para atingirmos nossos objetivos, na programação orientada a objetos não poderia ser diferente. Como já falamos anteriormente, programamos para automatizar processos do nosso dia a dia. Segundo a definição no dicionário Brasileiro da Língua Portuguesa Michaelis, “abstração é o processo pelo qual podemos observar uma ou mais características de um conjunto ou um todo, a fim de considerar aspectos e propriedades isoladamente “. Esta definição nos fala que não devemos nos preocupar com características menos importantes. Devemos nos concentrar, neste caso, apenas nos aspectos essenciais. As abstrações de- vem ser incompletas e imprecisas, por natureza, mas isto não significa que ela perderá sua utilidade. Esta é a sua grande vantagem, pois nos permite, a partir de um contexto inicial, modelar necessidades específicas. Isso possibilita flexibilidade no processo de programa- ção, pois é possível não trabalharmos com o conceito alvo diretamente, mas sim com suas abstrações. Para entender o ponto de vista orientado a objeto, considere um exemplo prático: uma cadeira. Cadeira é uma subclasse de uma classe muito maior que chamamos de Pe- caDeMobilia (peça de mobília). Cadeiras individuais são membros (usualmente chamados de instâncias) da classe Cadeira. Um conjunto de atributos genéricos pode ser associado a cada objeto de classe PecaDeMobilia. Por exemplo, todos os móveis tem um custo, dimensões, peso, localização e cor entre muitos outros atributos possíveis. Isso se aplica independentemente de estarmos falando de cadeira, mesa, um sofá ou um armário. Como Cadeira é um membros de PecaDeMobilia, Cadeira herda todos os atributos definidos para a classe. Tentamos dar uma definição de uma classe descrevendo seus atributos, de uma maneira bem-humorada, mas algo está faltando. Ele pode ser comprado, vendido, modi- ficado fisicamente (por exemplo, você pode cortar a perna de uma cadeira ou pintar de púrpura) ou movido de um lugar para o outro. Cada uma dessas operações (outros termos 10UNIDADE I Histórico e Conceitos Básicos são serviços ou métodos) modificará um ou mais atributos do objeto. Por exemplo, se o atributo localização for um item de dado composto definido como localização = edifício + piso + sala uma operação denominada move(), modifica um ou mais itens de dados (edifício, piso ou sala) que formam o atributo localização. Para isso move() deve ter “conhecimento” desse itens de dados. A operação move() poderia ser usada para uma cadeira ou mesa, já que ambas são instância da classe PecaDeMobilia . Operações válidas para a classe PecaDeMobilia - comprar(), vender(), pesar() - são especificadas como parte da definição de classe e herdadas por todas as instâncias da classe. A classe Cadeira (e todos os objetos em geral) encapsula dados (os valores de atributos que definem a cadeira), operações (as ações aplicadas para mudar os atributos da cadeira), outros objetos, constantes (configuração de valores) e outras informações re- lacionadas. Encapsulamento significa que todas essas informações são empacotadas sob um nome e podem ser reutilizadas como uma especificação ou componente de programa. 1.1.2. Reuso A pior prática em programação é a repetição de código. Esta prática leva a um código frágil e propício a resultados inesperados. Na aplicação, quanto mais códigos forem repetidos, mais difícil tornará a sua manutenção. Isso porque facilmente pode-se esquecer de atualizar algum ponto que logo levará a uma inconsistência, pois se é o mesmo código que está presente em vários lugares, é de se esperar que ele esteja igual em todos eles. E para alcançar este fundamento, a Orientação a Objetos provê conceitos que visam facilitar a sua aplicação. Existem outras formas, de alto nível, de reutilização de Orientação a Objeto, como por exemplo, herança. Com a herança é possível criar classes a partir de outras classes. A consequência disso, ocorre um reaproveitamento de códigos da chamada classe mãe (dados e compor- tamentos). A classe filha, além do que foi reaproveitada, neste caso, pode se acrescentar o que for necessário para si. 11UNIDADE I Histórico e Conceitos Básicos Já na associação, o reaproveitamento de código é diferente. Uma classe pede ajuda a outra para poder fazer o que não consegue fazer por si só. Em vez de repetir em si, o código que está em outra classe, a associação permite que uma classe forneça uma porção de código a outra. Desta maneira, a troca mútua culmina por evitar a repetição de código. 1.1.3. Encapsulamento Com o encapsulamento, podemos esconder a forma como algo foi feito, dando a quem precisa apenas o resultado gerado. Não importando para a quem requisitou algum processamento/comportamento ter conhecimento da lógica realizada para gerar o resultado final. Apenas o resultado final obtido que é relevante. A vantagem deste princípio é que as mudanças se tornam transparentes. Quem usa algum processamento não será afetado quando seu comportamento interno mudar. As linguagens estruturadas provêem este fundamento, mas é mais fácil para atingi-lo. Os con- ceitos de classe, método, entre outros, facilitam em muito a aplicação deste fundamento. A ocultação da informação é também outra característica do encapsulamento. Neste caso, ele blinda o aspecto interno do objeto em relação ao mundo exterior. Cria-se um invólucro ao redor das características, que tem como finalidade evitar resultados ines- perados, acessos indevidos, entre outros problemas. 12UNIDADE I Histórico e Conceitos Básicos 2. FALANDO SÉRIO SOBRE CLASSES “Classe é um conceito orientado a objeto que encapsula dados e abstrações pro- cedurais necessárias para descrever o conteúdo e comportamento de alguma entidade do mundo real. Abstrações de dados que descrevem a classe são envolvidas por uma ‘parede’ de abstrações procedurais capazes de manipular de certa maneira os dados. Em uma classe bem projetada, a única maneira de atingir os atributos e operar sobre eles, é passar através de um dos métodos que formam esta ‘parede’ “(Pressman 2011). Portanto, a classe encapsula os dados e o processamento que manipula os dados (os métodos que formam a ‘parede’). Isso possibilitao encapsulamento de informações e reduz o impacto de efeitos colaterais associado a mudança. Como os métodos tendem a manipular um número limitado de atributos, sua coesão é melhorada e porque a comuni- cação ocorre somente por métodos que formam a “parede”, a classe tende a ser menos fortemente acoplada em relação a outros elementos de um sistema. Podemos dizer, em outras palavras, que classe é uma descrição generalizada que descreve uma coleção de objetos similares. Por definição, objetos são instâncias de uma classe específica e herdam seus atributos e propriedades disponíveis para manipular os atributos. A Figura 01 Ilustra a diferença entre classe e objeto, apresentando a classe como um modelo, uma estrutura básica para onde cada objeto irá se basear para construir suas próprias características, porém todos com a mesmas estrutura básica. 13UNIDADE I Histórico e Conceitos Básicos Figura 01 - Diferença entre Classe e Objeto Uma superclasse (muitas vezes chamada de classebase) é a generalização de um conjunto de classes relacionadas a ela. Uma subclasse é uma especialização da super- classe. Por exemplo, a superclasse MotorVehicle é uma generalização das classes Truck, SUV, Automobile e Van. A subclasse Automobile herda todos os atributos de MotorVehicle, mas, além disso, incorpora atributos adicionais específicos apenas para automóveis. Essas definições, segundo Pressman, implicam a existência de uma hierarquia de classe na qual atributos e operações da superclasse são herdados por superclasses que podem, cada uma delas, acrescentar atributos e métodos “privados” adicionais. Por exemplo, as operações sitOn() e turn() podem ser privadas à subclasse Chair. 14UNIDADE I Histórico e Conceitos Básicos 3. ESTRUTURA DE UMA CLASSE Para ilustrar e fixar melhor a definição de classe, criaremos uma classe que en- capsula informações sobre veículos, com carro, vans e caminhões. Essa classe chamará Veículos e conterá três informações sobre veículo: número de passageiros suportado, a capacidade de armazenamento de combustível e o consumo médio de combustível Km/l. class Veiculo{ int passageiros;// número de passageiros int capacCombus; //capacidade do tanque de combustível em litros int kmpl; // consumo de combustível em quilômetro por litro } Através do operador class criou-se Veiculo. Você usará esse nome para declarar objeto do tipo Veiculo. Vale lembrar que uma declaração class é só uma descrição de tipo, ela não cria um objeto real. Portanto, o código anterior não faz existir um objeto do tipo Veiculo. Para realmente criar um objeto de tipo Veiculo você precisará utilizar uma instrução como mostra o código abaixo: Veiculo van = new Veiculo();//cria um objeto Veículo chamado van Após a execução dessa instrução, van será uma instância de Veiculo. Nós teremos portanto, uma realidade “física”. Não se preocupe, por enquanto, com os detalhes da ins- trução. 15UNIDADE I Histórico e Conceitos Básicos Sempre que criar uma instância de uma classe, você estará criando um objeto contendo sua própria cópia de cada variável de instância definida pela classe. Dessa ma- neira todos os objetos Veiculo conterão as suas próprias cópias das variáveis de instância passageiros, capacCombus e kmpl. Para ter acesso a essas variáveis, você deverá usar o que é normalmente chamado de Operador Ponto (.). O Operador Ponto faz um vínculo entre o nome de um objeto ao nome de um membro. Esta é a forma geral do operador ponto: objeto.membro O objeto, portanto, é especificado à esquerda e o membro é inserido à direita. Para atribuir, por exemplo, o valor 12 à variável capCombus de van, devemos usar a instrução: van.capacCombus = 12; Poderemos utilizar o operador ponto para acessar tanto variáveis quanto métodos. Este é o código completo que usa a classe Veiculo. /* Um programa que usa a classe Veiculo. Chame este arquivo de VeiculoDemo.java */ class Veiculo { int passageiros; // número de passageiros int capcCombus; // capacidade do tanque de combustível em litros int kmpl; // consumo de combustível em quilômetros por litro } } // Esta classe declara um objeto de tipo Veiculo. class VeiculoDemo { public static void main(String[] args) { Veiculo van = new Veiculo(); int range; // atribui valores a campos de van van.passageiros = 7; van.capcCombus = 50; van.kmpl = 12; //calcula a autonomia presumindo um tanque cheio de gasolina range = van.capcCombus * van.kmpl; System.out.println(“A Van pode levar “ + van.passageiros + “ passa- geiros com um alcance de “ + range + “ km de distância.”); } } 16UNIDADE I Histórico e Conceitos Básicos O arquivo contém o programa que deve ser chamado de VeiculoDemo.java, porque o método main() está na classe chamada VeiculoDemo e não na classe chamada Veiculo. Quando esse programa compilar, você poderá ver que dois arquivos .class foram criados um para Veiculo e um para VeiculoDemo. O compilador java insere automaticamente cada classe em seu próprio arquivo .class. Não há necessidade das classes Veiculo e Veiculo- Demo estarem no mesmo arquivo fonte. Você poderá inserir cada classe em seu próprio arquivo, chamados Veiculo.java e VeiculoDemo.java, respectivamente. Quando for executar o programa, você deverá executar VeiculoDemo.java. A saída a seguir será exibida: A Van pode levar 7 passageiros com um alcance de 600 km de distância. Examinemos um princípio básico, antes de avançarmos: cada objeto possui suas próprias cópias das variáveis de instâncias definidas por suas classes. O conteúdo das variáveis de um objeto pode ser diferente do conteúdo das variáveis de outro. Por exemplo, se você possui dois objetos Veiculo, cada um deles terá sua cópia de passageiros, capc- Combus e kmpl, e o conteúdo dessas variáveis será diferente entre os dois objetos. /* Um programa que usa a classe Veiculo. Chame este arquivo de VeiculoDemo.java */ class Veiculo{ int passageiros; // número de passageiros int capcCombus; // capacidade do tanque de combustível em litros int kmpl; // consumo de combustível em quilômetros por litro } } // Esta classe declara dois objeto do tipo Veiculo. class DoisVeiculo{ public static void main(String[] args) { Veiculo van = new Veiculo(); Veiculo esportivo = new Veiculo(); int range1, range2; // atribui valores a campos da van van.passageiros = 7; van.capcCombus = 50; van.kmpl = 12; // atribui valores a campos do veiculo esportivo esportivo.passageiros = 4; esportivo.capcCombus = 50; 17UNIDADE I Histórico e Conceitos Básicos esportivo.kmpl = 9; //calcula a autonomia presumindo um tanque cheio de gasolina range1 = van.capcCombus * van.kmpl; range2 = esportivo.capcCombus * esportivo.kmpl; System.out.println(“A Van pode levar “ + van.passageiros + “ passa- geiros com um alcance de “ + range1 + “ km de distância.”); System.out.println(“O Esportivo pode levar “ + esportivo.passageiros + “ passageiros com um alcance de “ + range2 + “ km de distância.”); } } A saída produzida por este programa é mostrada assim: A Van pode levar 7 passageiros com um alcance de 600 km de distância. O Esportivo pode levar 4 passageiros com um alcance de 450 km de distância. Os resultados dos dados da Van são totalmente diferente dos dados contidos em Esportivo. 3.1 Métodos Como já foi explicado anteriormente, as variáveis de instâncias e os métodos são componentes das classes. A classe Veiculo contém dados, mas não métodos. As classes somente de dados são perfeitamente válidas, a maioria das classes terão métodos. Os métodos são sub-rotinas que tratam os dados definidos pela classe e controlam, em muitos casos, o acesso a esses dados. Outras partes do programa, quase sempre, interagem com uma classe por seus métodos. Um método contém as instruções que definem suas ações. Cadamétodo executa apenas uma tarefa, em um código Java bem escrito. Cada método tem um nome, que é usado para chamar o método. De maneira geral, podemos dar o nome que quisermos, des- de que ele seja um identificador válido. Mas, as boas práticas de programação aconselham que devemos usar nomes descritivos. Devemos sempre lembrar que main() está reservado para o método que começa a execução do programa. Não se deve usar palavras-chave Java para nomear métodos como class, if, else, new, entre outros. 18UNIDADE I Histórico e Conceitos Básicos A representação dos métodos no texto, por uma convenção que se tornou comum quando se escreve sobre Java: o método terá parênteses após o seu nome. Por exemplo, se o nome de um método for getCar, ele será escrito da seguinte forma getCar() quando for usado em uma frase. Dessa maneira, ficará mais fácil distinguir nome de variáveis de nomes de métodos em nosso livro. A seguir a forma geral de um método: tipo-ret nome(lista-parâmetros){ // corpo do método } Nesta sintaxe, tipo-ret especifica o tipo de dados que será retornado pelo método. Poderá ser qualquer tipo de dado válido, inclusive os tipos de classes que você criar. Quando o seu método não precisar retornar um valor, o seu tipo de retorno deve ser void (vazio). O nome do método é especificado por nome. Poderá ser qualquer identificador válido exceto os já usados por outros objetos do programa atual. A lista-parâmetros é uma sequência de objetos, separados por vírgulas, compostos por tipo e identificador. Basicamente os parâmetros são variáveis que recebem o valor dos argumentos passados para o método quando ele é chamado. Quando o método não tiver parâmetros, a lista será vazia. 3.2 Adicionar um Método à Uma Classe Como expliquei no item anterior, normalmente os métodos de uma classe tratam e dão acesso aos dados da classe. Tendo isso em mente, lembra-se de que o método main() dos exemplos anteriores que calculavam a autonomia de um veículo multiplicados seu consumo pela capacidade do tanque de combustível? Tecnicamente correta, essa não é a melhor maneira de fazer esse cálculo. Será realizado mais adequadamente o cálculo da autonomia de um veículo pela própria classe Veiculo. Será fácil entender o porquê: a autonomia de um veiculo depende da capacidade do tanque de combustível e a taxa de consumo e esses dois valores serão encapsulado por Veiculo. Ao adicionar um método que calcule a autonomia à classe Veiculo, estará melhorando sua estrutura orientada a objetos. A versão a seguir de Veiculo, por exemplo, contém um método chamado range() que exibe a autonomia do veículo. // Adiciona range a Veiculo. class Veiculo { int passageiros; // número de passageiros int capcCombus; // capacidade tanque de combustível em litros int kmpl; // consumo de combustível em quilômetros por litro } 19UNIDADE I Histórico e Conceitos Básicos // Exibe a autonomia. void range() { System.out.println(“A autonomia é de “ + capcCombus * kmpl + “ km/L”); } class AddMeth { public static void main(String[] args) { Veiculo van = new Veiculo(); Veiculo esportivo = new Veiculo(); // atribui valores a campos de Van van.passageiros = 7; van.capcCombus = 50; van.kmpl = 12; // atribui valores a campos de veiculo Esportivo esportivo.passageiros = 4; esportivo.capcCombus = 50; esportivo.kmpl = 9; System.out.print(“A Van pode levar “ + van.passageiros + “ pessoas.”); van.range(); // exibe a autonomia da Van System.out.print(“O Esportivo pode levar “ + esportivo.passageiros + “ pessoas. “); esportivo.range(); // exibe a autonomia do Esportivo. } } Abaixo a saída que este programa gera: A Van pode levar 7 pessoas. A autonomia é de 600 km/L O Esportivo pode levar 4 pessoas. A autonomia é de 450 km/L Examinaremos agora os elementos-chave deste programa que foi apresentados a você. A primeira linha de range() é: void range() { É declarada nesta linha um método chamado range que não tem parâmetros. O tipo de retorno dele é void. Sendo desse tipo, range() não retornará nenhum valor para o chamador. A linha termina com a chave de abertura do corpo do método. O corpo de range() é composto pela linha: System.out.println(“A autonomia é de “+ capcCombus * kmpl + “ km/L”); 20UNIDADE I Histórico e Conceitos Básicos A autonomia do veículo é exibida na instrução multiplicando capcCombus por km/L. Como cada objeto de tipo Veiculo tem sua própria cópia de capcCombus e km/L, quando é chamado range(), o cálculo da autonomia usa as cópias dessas variáveis pertencentes ao objeto chamador. Quando a sua chave de fechamento é alcançada, o método range() termina a sua execução. Preste muita atenção para a linha de código que fica dentro do main(): van.range(); Essa instrução chama o método range() em van. O range() é chamado em relação ao objeto van, utilizando o nome do objeto seguido do operador ponto. Quando é chamado o método, o controle é transferido novamente para o chamador e é retomada a execução na linha de código posterior à chamada. A chamada a van.range() exibe nesse caso a autonomia do veículo definido por van. A chamada ao esportivo.range(), da mesma forma exibe a autonomia do veículo definido por esportivo. Sempre que é chamado, range() exibe a autonomia do objeto especificado. Dentro do método range() existe algo que é muito importante que são as variáveis de instâncias capcCombus e km/L são referenciadas diretamente, sem serem percebidas por um nome de objeto ou o operador ponto. Um método, quando usa uma variável de instância definida por uma classe, faz isso diretamente, sem referência explícita a um objeto e sem o uso do operador ponto. É fácil de você entender, se você pensar bem. Em outras palavras, um método sempre será chamado em relação a algum objeto de sua classe. Uma vez que essa chamada ocorrer, o objeto será conhecido. Dentro de um método, portanto, não precisaremos especificar o objeto novamente. Portanto, as variáveis capcCombus e km/L existentes dentro de range() referenciam implicitamente cópias dessa variáveis encontrada em que range() é chamado. 3.3 Tipos de Atributos Agora que os conceitos de classe e objeto foram explicados é que será possível apresentar os dois tipos de atributos e métodos, que ambos podem ser de instância ou estático. 21UNIDADE I Histórico e Conceitos Básicos Embora definidos na classe, os atributos de instância pertencem ao objeto. Por- tanto, só poderão ser acessados ou usados a partir de instâncias de uma classe, neste caso um objeto. Dessa maneira, cada um poderá ter valores distintos para seus atributos e conseguir armazenar os valores que necessitem. Por exemplo, se em uma classe chamada Pessoa existir um atributo de instância chamado nome, poderemos criar dois ou mais objetos e cada um deles terá um valor em particular para o seu atributo. Poderemos ter um objeto com o valor “Patrícia” para seu atributo nome, um outro objeto com valor “Antonio” para seu atributo nome, um outro objeto com valor “Augustus” para seu atributo nome. Se por uma coincidência ocorrer de dois objetos distintos terem o mesmo valor para o atributo nome, cada valor pertencerá isoladamente a cada objeto correspondente. Todo atributo é de instância, por padrão, desta forma para defini-lo, basta criar os atributos como já vem sendo feito. Vale lembrar o que dissemos anteriormente, o atributo estático pertence à classe e não ao objeto. Os atributos poderão ser acessados/usados via objeto, mas essa não é uma boa prática e deve ser desencorajado esse tipo de acesso. Pertencendo à classe e não ao objeto e devido a esse comportamento, ele se com- porta de forma oposta ao de instância, na qual, os valores armazenados neles pertencem a ela antes mesmos de existir um objeto. devido a isso, objetos distintos terãoo mesmo valor para esse determinado atributo. Por exemplo, utilizando a mesma classe Pessoa poderia ter um atributo chamado quantidaDeOlhos. Independente de qualquer objeto que seja criado, esse valor sempre será 2. Podemos relembrar os objetos citados anteriormente, no caso Patricia, Antonio e Augustus, cada um possui o seu valor de nome, mas todos possuem dois olhos. Neste caso o atributo quantidaDeOlhos poderia ser estático. Desta forma para definir os atributos, é necessário informar que ele é estático, a partir da palavra reservada static. A exemplificação do código a seguir nos dá esta definição: class Pessoa { String nome; static int quantidaDeOlhos; } 22UNIDADE I Histórico e Conceitos Básicos O método estático é pertencente à classe e não ao objeto, ele deve ser acessados diretamente através da classe. Repetindo, ele executa uma ação e ela será a mesma independente do objeto, pois antes de pertencer ao objeto, o método como estático, a palavra reservada estatic deve ser usada. class Pessoa { String nome; static int quantidaDeOlhos; String falar(){ return “Olá!”; } static void andar() { //implementação desejada } } 23UNIDADE I Histórico e Conceitos Básicos 4. MODIFICADORES DE ACESSO DE CLASSE E MEMBROS A classe fornece dois grandes benefícios. Primeiro, ela vincula os dados ao código que os trata. Esse aspecto, foi o que vimos até agora, nos tópicos anteriores. E em segundo, ela fornece o meio pelo qual o acesso a membros poderá ser controlado. É esse recurso que examinaremos agora, neste tópico. Java é um pouco mais sofisticada em sua abordagem, existem dois tipos básicos de membro de classes, que são públicos e privados. Um membro público poderá ter acesso livre por um código definido fora de sua classe. Esse tipo de membro que usamos até agora. O membro privado só poderá ser acessado por outros métodos definidos por sua classe. O acesso é controlado, com o uso de membros privados. Considerada a parte fundamental da programação orientada a objetos, a restrição do acesso a membros de uma classe, porque ela ajuda a impedir a má utilização de um objeto. Quando for permitido o acesso a dados privados somente por intermédio de um conjunto de métodos bem definidos, você poderá impedir que valores inapropriados se- jam atribuídos a esses dados, executando uma verificação de intervalo, por exemplo. Um código de fora da classe não poderá definir o valor de um membro privado diretamente. Você poderá também controlar exatamente como e quando os dados de um objeto serão usados. Dessa maneira, quando for corretamente implementada, uma classe criará uma espécie de “caixa preta” que poderá ser usada, mas cujo funcionamento interno não estará 24UNIDADE I Histórico e Conceitos Básicos aberto a alterações. Java disponibiliza de uma configuração de acesso padrão em que, os membros de uma classe ficam disponíveis livremente para outros códigos do programa. Para esses programas, portanto, a configuração de acesso padrão é basicamente pública. Aqui você verá como usar outros recursos de controle de acesso. 4.1 Modificadores de Acesso da Linguagem Java Como já vimos anteriormente, quando nenhum modificador de acesso for especifi- cado para o uso da classe, será presumido que se está sendo usado a configuração padrão. Dentro da linguagem Java existem três tipos de modificadores de acesso, que controlam o acesso a membros de uma classe, que são: public, private e protected. Nos ocuparemos de public e private neste tópico e o modificador protected ele só será útil quando houver herança de classes envolvidas. Estudaremos sobre esse modificador de acesso quando estudarmos herança, na Unidade II. Figura 02 - Funcionamento da declaração private para classes 25UNIDADE I Histórico e Conceitos Básicos Figura 03 - Funcionamento da declaração public para classes Quando o especificador public, conforme Figura 03, modifica o membro de uma classe, esse membro poderá ser acessado por qualquer código do programa, mesmo que o método tenha sido definido dentro de outras classes. Quando especificarmos como private, conforme Figura 02, o membro de uma classe, este só poderá ser acessado por outro membro de sua classe. Os métodos de classes diferentes não poderão acessar um membro private de outra classe. A configuração de acesso public é igual a padrão, quando nenhum modificador de acesso for usado, a não ser quando dois ou mais pacotes estejam envolvidos. Um pacote é um agrupamento de classes. Os pacotes são recursos organizacionais de controle de acesso a membros de uma classe, mas estudaremos com mais profundidade, nos capítulos futuros. Para os tipos de programas apresentados até aqui, o acesso public é igual ao acesso padrão. Um modificador de acesso deve preceder o resto da especificação de tipo de membro. Ele deve começar com a instrução de declaração do membro. Veja os exemplos abaixo: public String errMsg; private accountBalance bal; private boolean isError(byte status) { // ... 26UNIDADE I Histórico e Conceitos Básicos Observe o programa a seguir para entender os efeitos de public e private: // Acesso público versus privado. class MyClass { private int alpha; // acesso privado public int beta; // acesso público int gamma; // acesso padrão /* Métodos para acessar alpha. Não há problema em um membro de uma classe acessar um membro privado da mesma classe. */ void setAlpha(int a) { alpha = a; } int getAlpha() { return alpha; } } class AccessDemo{ public static void main(String[] args){ MyClass ob = new MyClass(); /* O acesso a alpha só é permitido por intermédio de seus métodos acessadores. */ ob.setAlpha(-89); System.out.println(“ob.alpha é “ + ob.getAlpha()); /* Você não pode acessar alpha dessa forma: ob.alpha = 10; // Errado! alpha é privado!*/ // Essas linhas estão corretas porque beta e gamma podem ser acessados. ob.beta = 78; ob.gamma = 89; } } Dentro da classe MyClass, alpha é especificado como sendo private, o beta está sendo especificado como public e gamma está usando acesso padrão, que é igual a especi- ficação de public. Como o acesso de alpha está especificado, ele não poderá ser acessado por código de fora de sua classe. Portanto, dentro da classe AccessDemo, alpha não poderá ser acessado diretamente. Deverão ser acessados por intermédio de seus métodos de acesso público setAlpha() e getAlpha(). Se for removido o símbolo de comentário do começo da linha abaixo, esse programa não poderá compilar devido à violação de acesso: 27UNIDADE I Histórico e Conceitos Básicos //ob.alpha = 10; // Errado! alpha é privado! /* O acesso a alpha só é permitido por intermédio de seus métodos de aces- sos. */ ob.setAlpha(-89); O acesso ao membro alpha por um código de fora de MyClass não é permitido, porém métodos internos definidos em MyClass poderão acessá-lo livremente, como os métodos setAlpha() e getAlpha(). Esse é o grande pulo do gato, um membro privado poderá ser acessado por outros membros da classe, mas não poderá ser acessado por um código de fora. Observe no código a seguir, com um exemplo prático, o programa implementa um array int “resistente a falhas” para ver como o controle de acesso pode ser aplicado. Nele é impedida a ocorrência de erros relacionados a limites, que evita gerar tempo excessi- vo quando a execução for gerada. Isso acontece com o encapsulamento do array como membro privado de uma classe, sendo permitido seu acesso apenas por intermédio de métodos membros. Qualquer tentativa de acessar o array fora de seus limites poderá ser evitada, com a tentativa falhando silenciosamente. O array será implementado pela classe FailSoftArray, que será mostrado a seguir: /* Esta classe implementa um array “resistentea falhas” que impede a ocorrência de erros de tempo de execução. */ class FailSoftArray{ private int[] a; // referência a array private int errval; // valor a retornar se get() falhar public int length; // length é público /* Constrói o array dados seu tamanho e o valor a ser * retornado se get() falhar. */ public FailSoftArray(int size, int errv){ a = new int[size]; errval = errv; length = size; } // Retorna o valor do índice especificado. public int get(int index){ if(ok(index)) return a[index]; return errval; } // Insere um valor em um índice. Retorna false em caso de falha. public boolean put(int index, int val){ if(ok(index)){ 28UNIDADE I Histórico e Conceitos Básicos a[index] = val; return true; } return false; } // Retorna true se index estiver dentro dos limites. private boolean ok(int index){ return index >= 0 & index < length; } } //Demonstra o array resistente a falhas. class FSDemo{ public static void main(String[] args){ FailSoftArray fs = new FailSoftArray(5, -1); int x; // exibe falhas silenciosas System.out.println(“Falhas silenciosas.”); for(int i=0; i < (fs.length * 2); i++) fs.put(i, i*10);/*O acesso ao array deve ser feito por intermédio de seus métodos de acesso.*/ for(int i=0; i < (fs.length * 2); i++) { x = fs.get(i);/*O acesso ao array deve ser feito por intermédio de seus métodos de acesso.*/ if(x != -1) System.out.print(x + “ “); } System.out.println(“”); // agora, trata as falhas System.out.println(“\nFalha com relatórios de erro.”); for(int i=0; i < (fs.length * 2); i++) { if(!fs.put(i, i*10)) System.out.println(“Index “ + i + “ fora dos limites”); } for(int i=0; i < (fs.length * 2); i++) { x = fs.get(i); if(x != -1) System.out.print(x + “ “); else System.out.println(“Index “ + i + “ fora dos limites”); } } } Examinando melhor esse código, podemos constatar três membros private dentro de FailSoftArray. O primeiro membro é a, que armazena uma referência ao array que con- terá realmente as informações. O segundo membro é errval, que é um valor a ser retornável 29UNIDADE I Histórico e Conceitos Básicos quando uma chamada get() falhar. O terceiro membro é o método private ok(), que determi- nará se um índice está dentro dos limites. Esses três membros portanto, somente poderão ser utilizados por membros da mesma classe FailSoftArray. Os membros a e errval só poderão ser usados por outros métodos da classe e ok() só poderá ser chamado por outros membros de FailSoftArray. O restante dos membros da classe são public e poderão ser chamados por qualquer código de um programa que use FailSoftArray. Quando for construído um objeto FailSoftArray, você deverá especificar o tamanho do array e o valor que desejará que te retorne se uma chamada get() falhar. O valor de erro, deverá ser um valor que de certa forma, não seria armazenado no array. A variável de instância length é public. Isso está de acordo com a maneira como Java implementa arrays. Precisamos apenas usar o membro length para obter o tamanho de um FailSoftArray. No entanto, é de grande valia ressaltar, que como length é público poderá ser mal utilizado. Por exemplo, nele poderia ser configurado um valor inapropriado. Você deverá chamar put() para armazenar um valor no índice especificado e cha- mar get() para recuperar um valor de um índice especificado ao usar um array FailSoftArray. Se por acaso, o índice estiver fora dos limites, put() retornará false e get() retornará errval. No mundo real, devemos sempre nos lembrar de restringir o acesso aos membro, principalmente variáveis de instância, é parte importante de uma bem sucedida programa- ção orientada a objetos. Você verá na próxima Unidade que o controle de acesso é ainda mais vital quando a herança estiver envolvida. 4.2 Passando Objetos para os Métodos Utilizamos nos exemplos até agora, tipos primitivos, como int, como parâmetros dos métodos. É correta e comum a prática da passagem de objetos para métodos. No exemplo a seguir, o programa define uma classe chamada block que armazena as dimensões de um bloco tridimensional. // Objetos podem ser passados para os métodos. class Bloco { int a, b, c; int volume; Bloco(int i, int j, int k){ a = i; b = j; 30UNIDADE I Histórico e Conceitos Básicos c = k; volume = a * b * c; } // Retorna true se ob definir o mesmo bloco. boolean mesmoBloco(Bloco ob){//Utiliza tipo de objeto no parâmetro if((ob.a == a) & (ob.b == b) & (ob.c == c)) return true; else return false; } // Retorna true se ob tiver o mesmo volume. boolean mesmoVolume(Bloco ob){//Utiliza tipo de objeto no parâmetro if(ob.volume == volume) return true; else return false; } } class PassOb { public static void main(String[] args) { Bloco ob1 = new Bloco(10, 2, 5); Bloco ob2 = new Bloco(10, 2, 5); Bloco ob3 = new Bloco(4, 5, 5); System.out.println((“ob1 mesmas dimensões que ob2: “ + ob1.mesmoBloco(ob2));//Passa um objeto System.out.println((“ob1 mesmas dimensões que ob3: “ + ob1.mesmoBloco(ob3));//Passa um objeto System.out.println(“ob1 mesmo volume as ob3: “ + ob1.mesmoVolume(ob3));//Passa um objeto } Esse programa deverá gerar a saída: ob1 mesmas dimensões que ob2: true ob1 mesmas dimensões que ob3: false ob1 mesmo volume as ob3: true Os métodos mesmoBloco() e mesmoVolume() fazem a comparação do objeto atual com o Bloco passado como parâmetro para o objeto chamador. Em mesmoBloco(), as dimensões dos objetos são comparadas e true é retornado apenas quando os dois blocos são idênticos. Em mesmoVolume(), os dois blocos só são comparados para verificar se eles possuem o mesmo volume. Observe que nos dois casos, ob específica Bloco como seu tipo. Mesmo que Bloco seja um tipo de classe criada pelo programa, é usada da mesma forma que os tipos internos de Java. 31UNIDADE I Histórico e Conceitos Básicos 4.3 Passando os Argumentos No exemplo anterior ficou demonstrado, que é simples a tarefa de passar um objeto para um método. Mas, existem algumas nuances na passagem de um objeto que não são mostradas no exemplo. Os efeitos da passagem de um objeto, em certos casos, serão vivenciados na passagem de argumentos que não são objetos. Para fica fácil o entendi- mento, será útil começarmos descrevendo resumidamente duas maneiras pelas quais uma linguagem de computador poderá passar um argumento para uma sub-rotina. A primeira maneira de um argumento poder ser passado é a chamada por valor. Ela copia o valor de um argumento no parâmetro formal da sub-rotina. As alterações feitas no parâmetro da sub-rotina, não têm efeito sobre o argumento da chamada. A segunda maneira é chamada por referência. Nessa abordagem, é passado para o parâmetro, uma referência a um argumento e não o valor do argumento. Essa referência , dentro da sub-rotina, é usada no acesso ao argumento real especificado na chamada. As alterações feitas no parâmetro afetarão o argumento usado para chamar a sub rotina. Você verá que Java, embora use a chamada por valor para passar argumentos, o efeito exato produzido difere entre a passagem um tipo primitivo ou um tipo de referência . Quando passamos um argumento tipo primitivo, como int ou double, para um mé- todo, seu valor será passado para o parâmetro. Uma cópia do argumento será feita e o que ocorre ao parâmetro recebedor do argumento, não tem efeito fora do método. Observe o exemplo a seguir: // Tipos primitivos são passados por valor. class Test{ /* Este método não causa alteração nos argumentos usados na chamada. */ void noChange(int i, int j) { i = i + j; j = -j; } } class CallByValue{ public static void main(String[] args) { Test ob = new Test();int a = 15, b = 20; System.out.println(“a e b antes da chamada: “ + a + “ “ + b); ob.noChange(a, b); 32UNIDADE I Histórico e Conceitos Básicos System.out.println(“a e b depois da chamada: “ + a + “ “ + b); } } A saída gerada deverá ser: a e b antes da chamada: 15 20 a e b depois da chamada 15 20 Como vimos no exemplo acima, as operações que ocorrem dentro de noChange() não têm efeito sobre os valores de a e b usados na chamada. Quando é passado um objeto para um método, a situação muda. Lembre-se, primeiro que, quando criarmos uma variável de um tipo de classe, estaremos criando uma referência. Quando passarmos um objeto como argumento, não estaremos passando o objeto propriamente dito, mas a referência que aponta para esse objeto. Se passarmos uma referência de objeto para um método, o parâmetro que a receber fará referência ao mesmo objeto referenciado pelo argumento. Na verdade os objetos serão passados para os métodos pela chamada por referência, já que só a referência é passada. As alterações no objeto dentro do métodos afetam o objeto usado como argumento. Ob- serve o exemplo abaixo: // Objetos são passados por suas referências. class Test { int a, b; Test(int i, int j){ a = i; b = j; } /* Passa um objeto. Agora, os valores ob.a e ob.b do objeto usados na chamada serão alterados. */ void change(Test ob){ ob.a = ob.a + ob.b; ob.b = -ob.b; } } class PassObjRef{ public static void main(String[] args) { Test ob = new Test(15, 20); System.out.println(“ob.a e ob.b antes da chamada: “ + ob.a + “ “ + ob.b); ob.change(ob); 33UNIDADE I Histórico e Conceitos Básicos System.out.println(“ob.a e ob.b depois chamada: “ + ob.a + “ “ + ob.b); } } Este programa deve gerar a saída: ob.a e ob.b antes da chamada: 15 20 ob.a e ob.b depois da chamada: 35 -20 Como podemos observar, neste caso, as ações que ocorreram dentro de change() afetaram o objeto passado para o método. De maneira resumida, quando uma referência de objeto é passada para um méto- do, esta referência será passada como uso da chamada por valor. O parâmetro receberá uma cópia da referência usada como argumento. Dessa maneira, tanto o parâmetro quanto o argumento referenciam o mesmo objeto, uma alteração através do parâmetro afetará o objeto referenciado pelo argumento. SAIBA MAIS Principais conceitos da Programação Orientada a Objetos Para reforçar o estudo dos conceitos de OO, trazemos a v. um artigo da DevMedia onde serão mostrados os principais conceitos do paradigma da programação Orien- tada a Objetos. Veja também como implementar os conceitos de POO com exemplos em Java. Vá para a internet no link abaixo e aproveite mais esse conteúdo! https://www.devmedia.com.br/principais-conceitos-da-programacao-orientada-a-ob- jetos/32285 https://www.devmedia.com.br/principais-conceitos-da-programacao-orientada-a-objetos/32285 https://www.devmedia.com.br/principais-conceitos-da-programacao-orientada-a-objetos/32285 34UNIDADE I Histórico e Conceitos Básicos REFLITA “As coisas simples devem ser simples e as coisas complexas, possíveis.” (Alan Kay) Com base nesta pensamento Alan Curtis Kay desenvolveu a linguagem SmallTalk totalmente baseada em Orientação a Objetos, no início da década de 70. Foi a pri- meira linguagem a implementar esse conceito, que até então estava somente no campo teórica da computação. Foi a partir deste trabalho de Alan que os conceitos de OO tomaram corpo e vida em outras linguagens. Dessa forma, fica a reflexão para todos nós, de como pensar a programação, e porque não a vida, como algo simples que deve ser fácil e acessível de usar e o complexo é uma mera junção de vários conceitos simples que se sobrepõe, mas nunca perdendo a capacidade de ser realizado. Referência: https://citacoes.in/citacoes/114432-alan-kay-as-coisas-simples-devem- -ser-simples-e-as-coisas-co/ 35UNIDADE I Histórico e Conceitos Básicos CONSIDERAÇÕES FINAIS Caro(a) aluno(a)! Nosso objetivo foi muní-lo de conceito e exemplos para facilitar o entendimento de um dos mais usado paradigma de programação na atualidade, Orientada a Objetos. Com uma rápida introdução aos conceitos e suas aplicações, você pode ver um pouco da história, com o surgimento através da formalização da teoria de simulação, que originou o Paradigma Orientado a Objetos. Você pode constatar as suas principais características e usabilidades, estudando os conceitos de Classes, sua criação e aplicações. Pode também entender a definição de classe, através do estudo de sua estrutura com exemplos práticos demonstrados nesta unidade. Com a utilização de estudos dirigidos, você pode analisar os exemplos apresentados de como são criados os objetos, que são uma extensão da classe. Outro ponto importante nessa unidade foram os métodos e seus atributos e onde devem ser aplicados. Além disso estudamos também os Modificadores de Acesso de Classes e Membros. Neste livro a OO vem acompanhada de exemplos na linguagem de Programação Java. Recomendamos que você aprofunde seus conhecimentos dessa linguagem através das dicas das leituras complementares, pois a prática conduz ao aperfeiçoamento. Portanto estude e pratique constantemente! Somente com dedicação ao estudo e a prática, você se tornará um excelente profissional. Mas não para por aí, na próxima unidade vamos estudar sobre os construtores e destrutores das classes, sobre polimorfismo e herança. Não fique parado, e entre nesse mundo OO com a gente! 36UNIDADE I Histórico e Conceitos Básicos Material Complementar Sinopse: Com uma abordagem clara e lógica, Programação com Java apresenta desde os aspectos básicos da linguagem até o conteúdo mais avançado. Os tópicos específicos – como o projeto orientado a objetos e a programação da GUI com Swing – são introduzidos apenas no momento apropriado. Códigos comentados e inúmeros exemplos e exercícios esclare- cem a finalidade e o uso dos elementos dos programas e testam a compreensão do conteúdo pelo leitor. Atualizado para Java 7 (JDK 7). Destaques: - Verificação do progresso e outros exercícios reforçam conteúdos básicos e fornecem feedback imediato sobre o aprendizado de conceitos chave. - As seções Pergunte ao especialista fornecem informações adicionais ou comentários interessantes relacionados ao tópico em questão. - As seções Tente isto fornece exemplos passo a passo que mostram os principais tópicos da programação em ação. Título: PROGRAMAÇÃO COM JAVA - UMA INTRODUÇÃO ABRANGENTE Autores: Herbert Schildt e Dale Skrien Editora: AMGH Editora Ltda. • Título: Programação Orientada a Objetos (POO) // Dicionário do Programador • Ano: Setembro de 2018. • Sinopse: Apresenta de uma forma bem didática e descritiva o conceito de Orientação a Objetos. • Link do vídeo: https://www.youtube.com/watch?v=QY0Kdg83orY. https://www.youtube.com/watch?v=QY0Kdg83orY 37UNIDADE I Histórico e Conceitos Básicos REFERÊNCIAS NANCE, Richard E.. A history of discrete event simulation programming languages. The Second Acm Sigplan Conference On History Of Programming Languages - Hopl-ii, [s.l.], p.149-175, 1993. ACM Press. http://dx.doi.org/10.1145/154766.155368. Dicionário Brasileiro da Língua Portuguesa - https://michaelis.uol.com.br. PRESSMAN, Roger S. Engenharia de software: uma abordagem profissional. 7 ed. Porto Alegre: AMGH Editora, 2011. CARVALHO, Thiago Leite. Orientação a objetos. Casa do Código, 2017. TOCHER, Keith Douglas. The art of simulation. London: English Universities Press, 1967 http://dx.doi.org/10.1145/154766.155368 https://michaelis.uol.com.br 38 Plano de Estudo: 1. Linguagem de modelagem unificada - UML 2. Construtores e destrutores 3. Herança - hierarquia e as relações entre os objetos 4. Polimorfismo - métodos com a mesma assinatura em classes distintas 5. Consideraçõesfinais Objetivos de Aprendizagem: • Introduzir conceito sobre a Linguagem de Modelagem Unificada - UML. • Fornecer conceitos sobre a utilização de Construtores e Destrutores. • Conceituar e contextualizar sobre a Herança entre os métodos e variáveis herdadas de outras classes. • Estabelecer a importância do Polimorfismo para o reaproveitamento e a simplificação do código. UNIDADE II UML e a Organização das Informações Professor Mestre Ricardo Vieira 39UNIDADE II UML e a Organização das Informações INTRODUÇÃO Esta unidade inicia os estudos com uma breve introdução sobre a Linguagem de Modelagem Unificada - UML. Embora a linguagem possua uma quantidade maior que doze tipos de diagramas diferentes, você verá que trataremos apenas de um tipo de diagrama, o Diagrama de Classe e suas interfaces, dentro da Orientação a Objetos. Para melhorar o desenvolvimento de um código Orientado a Objetos, você poderá ver e praticar com os estudos teóricos e praticando com os exemplos apresentados, como uma maneira de identificar os conceitos apresentados nesta unidade. Agora, vamos em frente! E continuando os estudos a respeito da Orientação a Objetos, só lembrando que daqui para frente, você deverá estudar continuamente. Até quando? Até o fim de sua vida, porque a evolução das tecnologias não para!!! 40UNIDADE II UML e a Organização das Informações 1. LINGUAGEM DE MODELAGEM UNIFICADA - UML Para ajudar no entendimento sobre o uso adequado da herança, poderá nos ajudar, se tivermos um diagrama que nos mostra os relacionamentos entre classes de um projeto. Mas antes mesmo de entrarmos nesse assunto de extrema importância e que merece muita atenção, faremos um introdução nos diagramas de classes UML. A UML (Unified Modeling Language) é uma Linguagem de Modelagem Unificada padrão para a diagramação da estrutura de um software. Independente tanto da linguagem de programação quanto de processos de desenvolvimentos, ela é muito usada na imple- mentação de um sistema. A UML possui mais de uma dúzia de diagramas e o diagrama de classe é uma delas. O diagrama de classe exibe classes e interfaces e os relaciona- mentos entre elas, que independe da linguagem utilizada. Fornecendo uma visão estática de classes, interfaces e seus relacionamentos, em vez de exibir uma visão dinâmica das interações entre objetos dessas classes. A UML surgiu em meados da década de 1990, com a união de três métodos de modelagem que são: o Método de Booch (Booch Method) de Grady Booch, o Método OMT (Object MOdeling Technique) de Ivar Jacobson e o Método OOSE (Object-Orien- ted Software Engineering) de James Rumbaugh. Estes eram os métodos de modelagem Orientado a Objetos mais usados pelos desenvolvedores de softwares da época. A união desses três métodos foi incentivada e financiada pela Rational Software. A primeira versão da UML propriamente dita, foi em 1996. Após o lançamento da UML, muitas empresas de 41UNIDADE II UML e a Organização das Informações desenvolvimento de softwares, passaram utilizar e contribuir para o seu desenvolvimento, fornecendo sugestões para ampliar e melhorar a linguagem. Na Figura 04 é mostrada uma notação UML para as subclasses. É chamado de relacionamento de Generalização em UML, a seta que aponta da subclasse para a super- classe. Figura 04 - A notação UML para a subclasse e superclasse. 1.1. Diagrama de Classes Um diagrama de classe é uma representação da estrutura e relações das classes que servem de modelo para o objeto. É um conjunto de objetos que possuem as mesmas características, sendo assim, fica mais fácil identificar os objetos e agrupá-los de forma a encontrar suas respectivas classes. Um diagrama de classe, exemplificado na Figura 05, pode ser representado por uma caixa retangular, dividida em três seções. A primeira, a do topo, fornece o nome da classe. A segunda seção, a do meio, fornece os atributo ou as propriedades mantidos pelos objetos da classe. Essas propriedades podem ser abstrações dos dados ou estado de um objeto. São implementadas geralmente com uso de variáveis de instâncias. E terceira, a seção inferior, fornece as operações de uma classe. Na linguagem de programação Java correspondem aos métodos e construtores. Figura 05 - Representação do diagrama de classe e o exemplo com o diagrama de classe Carro. 42UNIDADE II UML e a Organização das Informações Para o desenvolvimento do nosso diagrama de classe, você precisará de um ce- nário onde realizará um passo a passo até abstrair todas as classes, a partir deste ponto, poderá efetuar as ligações e cardinalidades. Por exemplo, vamos imaginar um diagrama de uma classe Person apresentado na Figura 06. Só para relembrar como vimos anteriormente. Na primeira seção, está fornecido o nome da classe, que no nosso caso é Person. Na segunda seção do diagrama, exibe um atributo name que é do tipo string e um atributo birthDate de tipo date. Na linguagem Java poderemos implementar esses dois atributos com a inclusão de duas variáveis de instâncias na classe Person, uma variável chamada name de tipo String e uma outra variável chamada birthDate de tipo Date. A terceira, Imaginando ainda, nesse nosso dia- grama também nos mostra, que essa classe tem um construtor com dois parâmetros, um é o método getName() que está sem parâmetros e um outro é o método getBirthDate() que também está também sem parâmetros, que nos retorna dois valores, um do tipo String e um do tipo Date, respectivamente. Vamos imaginar outras coisas neste nosso diagrama: O símbolo “-” na frente dos atributos indica que eles são privados. O símbolo “+” na frente das operações indica que elas são públicas. Os tipos dos atributos, parâmetros e os tipos de retorno das operações são forne- cidos após os nomes do elemento e separados por dois pontos. A implementação dessas operações e atributos não é concluída na caixa, porque geralmente um diagrama UML não se preocupa com um nível tão baixo de detalhes. Figura 06 - O diagrama de uma classe Person. Poderá ser omitida qualquer uma das partes de uma classe do diagrama, exceto o seu nome. É recomendado que o diagrama deixe de fora todos os detalhes que não sejam relevantes, para evitar desorganização e confusão. É importante lembrar que, se as operações não forem mostradas, isso não quer dizer que ela não tenha operações, as 43UNIDADE II UML e a Organização das Informações operações não são relevante nesse diagrama. Na UML, os diagramas de classes não exibem apenas as classes e interfaces, mostram também os relacionamentos entre elas. Uma associação é um relacionamento es- trutural entre duas classes. E se os objetos de uma classe tiverem uma referência a objetos de outra classe, ou se você precisar navegar de objetos uma classe para objetos de outra, poderá representar a conexão entre as classes com uma associação, que é desenhada em diagramas de classes UML como linha entre as caixas de classes. Você poderá encontrar a definição completa da UML, na Especificação da Lingua- gem de Modelagem Unificada da OMG, diretamente no site da OMG (www.omg.org). 44UNIDADE II UML e a Organização das Informações 2. CONSTRUTORES E DESTRUTORES Você pode ver nos exemplos de instanciação (inicialização) de objetos foram usa- das a palavra reservada new da seguinte forma: Veiculo van = new Veiculo(); O operador new, conforme foi comentado anteriormente, é o responsável pelo processo de instanciação da objeto, mostrando de uma maneira simples de atribuir valores default a um objeto. A declaração anterior pode ser lida da seguinte maneira: construa o objeto van (do tipo Veiculo) com valores default. O método construtor , como o próprio nome diz, é o responsável pela construção de um objeto com determinados valores. Na linguagem Java se um construtor não for definido,será assumido um construtor default da própria linguagem, em que as variáveis serão inicializadas com os conteúdos default, onde as variáveis numéricas receberão zero, valores lógicos receberão false e objetos receberão null. O construtor deverá possuir sempre o mesmo nome de sua classe e será sintaticamente semelhante a um método, quando for declarado. Uma classe poderá conter de 0 a N construtores declarados ou definidos, dependendo das suas necessidades. Usaremos normalmente, um construtor para fornecer valores iniciais para as variáveis de instâncias definidas pela classe ou para executar algum outro procedimento de inicialização necessário à criação de um objeto totalmente formado. 45UNIDADE II UML e a Organização das Informações A responsabilidade do método construtor é alocar espaço na memória para a mani- pulação do objeto e poderá conter também a chamada para outros métodos, possibilitando a criação de objetos mais complexos. Figura 07 - Um exemplo simples que utiliza um construtor. No exemplo apresentado na Figura 07, o construtor de MyClass é: MyClass() { x = 10;} Esse construtor atribuiu o valor 10 à variável de instância x de MyClass. Ele será chamado por new quando um objeto for criado. Por exemplo, na linha MyClass t1 = new MyClass(); O construtor MyClass() é chamado e o objeto resultante é atribuído a t1, com t1.x recebendo o valor 10. O mesmo ocorre para t2. Após a construção, t2.x terá o valor 10. Portanto a saída do programa será: 10 10. 46UNIDADE II UML e a Organização das Informações 2.1. CONSTRUTORES PARAMETRIZADOS Usou-se, no exemplo da Figura 07, um construtor sem parâmetros. Embora em algumas situações isso seja adequado quase sempre você precisará de um construtor que aceita um ou mais parâmetros. São adicionados os parâmetros ao construtor do mesmos modo como são adicionados a um método: apenas os declare dentro de parênteses após o nome do construtor. Por exemplo: Figura 08 - No exemplo, MyClass recebe um construtor parametrizado. A saída do programa apresentado na Figura 08 é: 10 88. Nessa versão do programa, o construtor MYClass() define um parâmetro chamado i, que é usado para inicializar a variável de instância x. Logo, quando a linha MyClass t1 = new MyClass(10); é executada, o valor 10 é passado para i, que é então atribuído a x. 47UNIDADE II UML e a Organização das Informações 2.2. Adicionando um construtor à classe Vehicle Você pode melhorar a classe Veiculo adicionando um construtor que inicialize automaticamente os campos passageiros, capacCombus e kmpl quando um objeto for construído.Observe como os objetos são criados na Figura 09: Figura 09 - Um construtor é adicionado a Classe Veiculo. A Van e o Sportivo, ambos são inicializados pelo construtor Veiculo() quando são instanciados (criados). Cada objeto é inicializado como especificado nos parâmetros de seu construtor. Por exemplo: Veiculo sportivo = new Veiculo(2, 14, 12); Os valores 7, 16, e 21 são passados para o construtor Veiculo() quando new cria o objeto. A cópia de passageiros, capacCombus e kpl do sportivo terá os valores 7, 16, e 21 respectivamente. 48UNIDADE II UML e a Organização das Informações 2.3. Revisando o Operador New Agora que você aprendeu mais sobre as classes e seus construtores, vamos exa- minar com detalhes o operador new. Uma atribuição em contexto, o operador new tem esta forma: var-classe = new nome-classe(lista-arg); No exemplo, var-classe é uma variável do tipo de classe que está sendo instanciada (criada). Aqui, nome-classe é o nome da classe que está sendo instanciada. O nome da classe seguido por um parêntese (que poderá estar vazio) com uma lista de argumentos, que especifica o construtor da classe. New usará o construtor padrão fornecido por Java, se uma classe não definir seu próprio construtor. Logo, new pode ser usado para instanciar um objeto de qualquer tipo de classe. O operador new retorna uma referência ao objeto recém-criado, que nesse caso, é atribuído a var-clase. 49UNIDADE II UML e a Organização das Informações 3. HERANÇA - HIERARQUIA E AS RELAÇÕES ENTRE OS OBJETOS 3.1 Introdução aos Conceitos Relacionais e Herança Os conceitos relacionais são responsáveis por possibilitar a criação de classes a partir, ou com a ajuda , de outros classes. O conceito de herança é a possibilidade de representar algo que existe no mundo real. Um clássico exemplo disto é quando vimos na escola, na aula de ciências, estudando sobre a classificação biológica. Ela apresentava a seguinte divisão que era feita entre os seres vivos: Reino, Filo, Classe, Ordem, família, Gênero, Espécie. A divisão, do nível mais baixa herda o que for necessário da divisão superior, isto ocorre porque a mais baixa é um subtipo da divisão acima. A Espécie de Gênero, que por sua vez herda da Família e assim por diante. No nosso caso, seres humanos, nossa classificação desta estrutura seria: Reino: Animalia Filo: Chordata Classe: Mammalia Ordem: Primates Família: Hominidae 50UNIDADE II UML e a Organização das Informações Gênero: Homo Espécie: Homo Sapiens. Homo Sapiens herda de Homo. que herda por sua vez de Hominidae e assim por diante. Um outro exemplo mais simples é que todos nós herdamos algo de nossos pais e eles herdaram dos pais deles e assim por diante. Na Orientação a Objetos, como o próprio nome sugere, herança se refere a algo que é herdado. Na linguagem de programação Java, a herança ocorre quando uma classe passa a herdar características como variáveis e métodos definidos em outra classe espe- cificada como sendo sua ancestral ou superclasse. A técnica da herança utilizada em Java possibilita o compartilhamento ou o aproveitamento de recursos definidos em outra classe anteriormente. A classe que fornece os recursos recebe o nome de superclasse e a classe que recebe os recursos, são chamados de subclasse. Outro termo que envolve herança é a especialização. Quando uma classe herda características de outra classe, ela pode implementar partes específicas não contempladas na classe original - superclasse - tornando-se especializada em algum processo. Todas as classes criadas na linguagem Java, recebem recursos da classe Object, a classe “mãe” da linguagem. Esse processo é transparente a quem programa, é de maneira automática que ocorre, sem que se dê conta disso. Para melhor compreensão observe o exemplo da classe Sapato, na Figura 10, a classe define apenas três atributos públicos: Figura 10 - Listagem da classe Sapato. Verifique agora o exemplo da classe UsaSapato na Figura 11. Na linha 4 é de- clarado e instanciado um objeto chamado Sapato. Porém, nas linhas 5, 6 e 7 são usados os métodos getClass(), getSimpleName() e hashCode(). Você deve estar perguntando de onde é que surgiram esses métodos? Eles não existem na classe Sapato! Esses métodos e alguns outros foram herdados no momento de sua criação. 51UNIDADE II UML e a Organização das Informações Figura 11 - Listagem da classe UsaSapato. Funcionalidades comentadas da classe UsaSapato: Na linha 4, é criado o objeto Sapato a partir da classe Sapato. ● Na linha 5, utiliza o método getClass() da classe Object, herdado pela classe Sapato e disponibilizado para o objeto sapato. O método é apresentado em tela o nome do pacote seguido do nome da classe. Com esse método torna possível descobrir, em tempo de execução, qual é o tipo do projeto e qual classe ele pertence ou ainda a partir de qual classe ela foi criada. ● Na linha 6, é similar ao anterior, porém retorna o nome da classe por meio do método getSimpleName(). ● Na linha 7, é utilizado o método hashCode() da classe Object. O método retorna um número único para o objeto, um número diferente para cada objeto. Esse método é utilizado para agilizar o processo de armazenamento e recuperação em estruturas de dados complexas, que nãoabordaremos aqui. 3.2. Aspectos Básicos de Herança A linguagem de programação Java dá suporte à herança permitindo que uma classe incorpore outra classe em sua declaração. Esta funcionalidade é construída com a utilização da palavra-chave extends. A subclasse traz, portanto, acréscimos (estende) à superclasse. Começaremos com um exemplo, Na Figura 12, que ilustra vários dos recursos-cha- ves de herança. O programa a seguir cria uma superclasse chamada DuasDimensoes, que armazena a largura e altura de um objeto bidimensional e uma classe chamada Triangulo. Observe como a palavra-chave extends é usada para criar uma subclasse 52UNIDADE II UML e a Organização das Informações Figura 12 - O programa cria uma superclasse chamada DuasDimensoes.(Parte 1) Este exemplo se estende pela Figura 13, que ilustra vários dos recursos-chaves de herança. O programa a seguir cria uma superclasse chamada DuasDimensoes, que armazena a largura e altura de um objeto bidimensional e uma classe chamada Triangulo. Observe como a palavra-chave extends é usada para criar uma subclasse: Figura 13 - O programa cria uma superclasse chamada DuasDimensoes. (Parte 2) 53UNIDADE II UML e a Organização das Informações A saída do programa é: Informações para t1: O triângulo é preenchido Largura e altura são 4.0 e 4.0 Área é 8.0 Informações para t2: O triângulo é delineado Largura e altura são 8.0 e 12.0 A área é 48.0 No programa apresentado no exemplo DuasDimensoes define os atributos de uma forma bidimensional de forma genérica, como um quadrado, retângulo ou triângulo. A classe Triangulo cria um tipo específico de DuasDimensoes, nesse caso, um triângulo. Ela inclui tudo que pertence a DuasDimensoes e adiciona o campo style, o método area() e o método showStyle(). O estilo do triângulo é armazenado em style. Poderá ser qualquer string que descreva o triângulo, como “cheio”, “contorno”, “transparente” ou até algo como “símbolo de aviso”, “isósceles” ou “arredondado”. O método area() calcula e retorna a área do triângulo e showStyle() exibe seu estilo. Como a classe Triangulo inclui todos os membros de sua superclasse, DuasDi- mensoes, pode acessar largura e altura dentro de area(). Dentro de main(), os objetos t1 e t2 podem referenciar largura e altura diretamente, como se ele fizesse parte da classe Triangulo. DuasDimensoes ainda que seja a superclasse de Triangulo, ela também é uma classe autônoma totalmente independente. Ser a superclasse de uma subclasse não sig- nifica não poderá ser usada separadamente. A forma geral de uma declaração class que herda uma superclasse é mostrada aqui: class nome-subclasse extends nome-superclasse { //corpo da classe } 54UNIDADE II UML e a Organização das Informações Você só poderá especificar uma única superclasse para qualquer subclasse que criar. A linguagem de programação Java não dá suporte à herança de várias superclasses na mesma subclasse. Você poderá criar, no entanto, uma hierarquia de herança em que uma subclasse passe a ser uma superclasse de outra subclasse. Nenhuma classe poderá ser a superclasse de si mesma. 3.3. A Grande Vantagem da Herança A grande vantagem da herança é que, uma vez que você tenha criado uma super- classe que defina os atributos comuns a um conjunto de objetos, ela poderá ser usada para criar qualquer número de subclasses mais específicas. Cada subclasse poderá especificar com mais precisão sua própria classificação. Na Figura 14 esta é outra subclasse de Duas- Dimensoes que encapsula retângulos: Figura 14 - Subclasse de DuasDimensoes que encapsula retângulos. A classe Retangulo inclui DuasDimensoes e adiciona os métodos ehQuadrado(), que determina se o retângulo é quadrado e area(), que calcula a área de um retângulo. Observe que Retangulo não tem um campo style ou um método showStyle(). Embora Triangulo adicione esses membros, isso não significa que Retangulo ou qualquer outra classe de DuasDimensoes, também deve adicioná-los. Exceto por compartilhar a mesma superclasse, cada subclasse é independente. As subclasses podem fornecer membros semelhantes, como é o caso do método area(). Mesmo com uma implementação diferente, tanto Triangulo quanto Retangulo fornecem esse método. 55UNIDADE II UML e a Organização das Informações 3.4. Acessando Membros e Herança Você viu anteriormente que, com frequência a variável de instância de uma clas- se é declarada como private para não poder ser usada sem autorização ou adulterada. Quando é herdada uma classe não invalida a restrição de acesso private. Mesmo que uma subclasse inclua todos os membros de sua superclasse, não poderão ser acessados os membros declarados como private. Na Figura 15, largura e altura foram tornadas privadas, em DuasDimensoes, Triangulo não poderá acessá-las. Veja: Figura 15 - Membros privados de uma superclasse não podem ser acessados por uma subclasse. No exemplo apresentado, a classe Triangulo, não será compilada, porque a referên- cia largura e altura dentro do método area() causa uma violação de acesso. Como largura e altura foram declaradas como private em DuasDimensoes, só poderão ser acessadas por outros membros de DuasDimensoes. As subclasses poderão ser acessá-las. Você deverá lembrar de que o membro de uma classe que foi declarado como private, permanecerá sendo private de sua classe. Não poderá ser acessado por nenhum código de fora da classe, inclusive subclasses. Você pode achar, à primeira vista, que o fato das subclasses não ter acesso aos membros privados das superclasses é uma restrição grave que impediria o uso de membros privados em muitas situações. Mas isso não é verdade. Como foram comentados anterior- mente, normalmente os programadores que utilizam a linguagem Java, usam métodos para dar acesso às variáveis de instância privadas de uma classe. Uma nova versão das classes DuasDimensoes e Triangulo que usam métodos para acessar as variáveis de instâncias 56UNIDADE II UML e a Organização das Informações privadas largura e altura, são apresentados na Figura 16 e 17: Figura 16 - As classes DuasDimensoes e Triangulo usando métodos acessadores para configurar e exami- nar membros privados. Figura 17 - As classes DuasDimensoes e Triangulo usando métodos acessadores para configurar e exami- nar membros privados.(continuação) 57UNIDADE II UML e a Organização das Informações 4. POLIMORFISMO - MÉTODOS COM A MESMA ASSINATURA EM CLASSES DISTINTAS 4.1. Introdução: A Herança e o Polimorfismo Novos métodos e atributos podem ser adicionados sem alteração das interfaces de programação e de usuário existentes de uma determinada classe, através dos mecanismos de encapsulamento, constituindo um poderoso mecanismo de extensão de classes, mas o mecanismo de herança oferece possibilidades muito maiores. A herança, como você pode ver no capítulo anterior, permite que novas classes sejam instanciadas e adicionadas a uma hierarquia sem a necessidade de qualquer modi- ficação do código existente das classes e das aplicações que utilizam estas classes, pois cada classe define estritamente, entre seus próprios métodos e atributos. Com as novas classes adicionadas a hierarquia pode estender, especializar ou restringir o comportamento das classes originais. Mas se você analisar a hierarquia das classes no sentido inverso, isto é, se di- rigindo da classe de nível inferior para a classe de nível superior, você perceberá que ocorre a generalização das diferentes classes relacionadas. Cada classe da hierarquia poderá assumir o mesmo comportamento da superclasse, sendo tratada como tal. Se a superclasse modificar sua estrutura, todas as classes serão afetadas igualmente. Com isso 58UNIDADE II UML e a Organização das Informações você poderá observar que uma classe da hierarquia poderá assumir diferentes formas ou funcionalidades,
Compartilhar