composição de software orientado a objetos

42
Grupo EvoFavo, Projeto Monkey Buzziness Equipe de projeto e arquitetura de Software Composição de software orientado a objetos Revisão 1.0

Upload: albertoprb

Post on 06-Jun-2015

2.771 views

Category:

Documents


3 download

DESCRIPTION

Documento elaborado sobre orientação a objetos no projeto evofavo

TRANSCRIPT

Page 1: Composição de software orientado a objetos

Grupo EvoFavo, Projeto Monkey Buzziness

Equipe de projeto e arquitetura de Software Composição de software orientado a objetos

Revisão 1.0

Goiânia, fevereiro de 2007.

Page 2: Composição de software orientado a objetos

Sumário

Parte I Determinando o espaço de trabalho

Palestra I 1. Conceitos de Orientação a objetos

2. Herança

Palestra II1. Sistemas de tipos2. Metodologias de desenvolvimento de software

Parte II Entendendo o problema

Palestra III 1. Determinando os requisitos 2. Analisando o problema

Parte III Fazendo o design da solução

Palestra IV 1.Design da arquitetura

2.Escolhendo tecnologias

Palestra V 1.Desenhando o Subsistema

2.Design patterns overview

Palestra VI 1.Especificando as interfaces de classes overview

2.Teste contínuo

Parte IV Estudo de Caso I

Palestra VII Palestra VIII

Parte V Desenvolvimento de softwares orientados a interfaces

Palestra IX 1.Introdução as interfaces

2.Contratos de interfaces3.Ingredientes das interfaces4.O que deve estar presente em uma interface5.Herança e interfaces6.Interfaces remotas

Palestra X1.Interfaces e as metodologias de desenvolvimento

Page 3: Composição de software orientado a objetos

2.Interfaces no mundo real, estudo de casos3.Interfaces e patterns

Parte VI Design Patterns – Tópicos Avançados

Palestra XI 1. Sobre patterns 2. The observer pattern 3. The decorator pattern 4. The factory pattern

5. The singleton pattern6. The command pattern

Palestra XII7. The adapter and facade patterns8. The template method pattern9. The iterator and composite patterns

Palestra XIII10. The state pattern11. The proxy pattern

Palestra XIV12. Compound pattern13. Vivendo melhor com patterns14. Outros patterns

Parte VII Usando XML para Desenvolvedores de Software

Palestra XVPalestra XVI

Tempo esperado término: Julho/07

Page 4: Composição de software orientado a objetos

Introdução

O objetivo desse curso é ensinar análise e design de software orientado a objetos. Portanto nosso intuito é modelar projetos de aplicações independente de linguagem, portanto reprodutível em qualquer linguagem orientada a objetos como Java, C++, C#.

O treinamento será de preferência usando recursos interativos, ou seja vídeo aulas, exercícios práticos, e estudo de casos. Com isso desejamos que o material seja assimilado aos poucos integrando-se ao pensamento do desenvolvedor.

Materiais teóricos serão acrescentados a esse documento a medida que o curso evolui. Portanto tratem esse manual como um handbook para consultar toda hora que tiver que analisar ou projetar e até mesmo programar um sistema.

As palestras presenciais serão na medida do possível reduzidas para garantir além da reprodutibilidade do conteúdo que todos os tópicos sejam vistos.

Espero montar um material de extrema qualidade e que seja uma referencia constante para todos envolvidos no projeto ou que desejem aplicar essas informações em outros projetos. Portanto sempre terei em mente a simplicidade na exposição dos conteúdos.

O meu alvo é programadores com alguma experiência em orientação a objetos e que conheçam as estruturas básicas de uma linguagem OO como Java ou C#.

Diz um provérbio que você não sabe um assunto até que possa explicá-lo a uma criança de 8 anos de idade. Minha intenção é mostrar que esse provérbio esta correto e conto com o seu feedback para isso.

A melhor forma de ler o material é seguindo a ordem dos capítulos mas nada impede do leitor mais interessado de pular alguns conceitos. Iniciamos nosso estudo com as questões básicas da orientação a objetos e a construção de sistemas robustos e reaproveitáveis. Seguimos abordando a análise do sistema. Em seguida estudamos o design em alto nível ou seja o design da arquitetura do software e a escolha das tecnologias a serem usadas, depois passamos ao design dos subsistema ao qual o leitor deve estar mais familiarizado. Por fim avançamos sobre tópicos avançados como design patterns e o uso de XML na comunicação entre os componentes do software. A notação UML será incrementada durante o curso.

Muitos conceitos de design abordados aqui o leitor pode considerar familiarizado porém convido você a refletir esses conceitos e garantir se realmente está produzindo softwares orientados a objetos.

Nota aos integrantes do grupo EvoFavo: Esse material deve abordar as questões técnicas do projeto de software sendo que as questões de negócio devem ser abordadas pelo gerente do projeto. Minha intenção não é precipitar o design e fazê-lo apenas depois que a maioria estiver bastante a vontade com as principais idéias aqui apresentadas. Não durmam ou converse nas palestras, nem finja que está entendendo, caso algum tópico lhe pareça obscuro pergunte imediatamente, não percamos nosso tempo. Lembrem-se que a primeira iteração não temos tempo marcado. Eu proponho que após terminarmos a primeira iteração e termos uma noção mais sólida de projeto de software que façamos várias atividades para verificar se todos dominam o básico de cada área, garantindo assim que o pessoal está qualificado, antes de prosseguir. Podemos a partir do resultado identificar áreas falhas e treinar o pessoal.

Page 5: Composição de software orientado a objetos

Alberto Paulo Rabelo Barcelos

Parte I Determinando o espaço de trabalho

Palestra I

Conceitos de Orientação a objetos

Introdução

Nos dias atuais praticamente todos softwares são orientados a objetos. Mas nemsempre se consegue com facilidade escrever na prática códigos orientados a objetos. Tal atividade requer treinamento e reflexão. Há muito mais atividades no desenvolvimento de software que escrever linhas de código. Temos de fazer análise de negócios, requisitos do software, design da arquitetura e o design de baixo nível, entre outras. Portanto nada mais natural que basear o desenvolvimento em uma nova abstração chamada objeto. Os objetos reduzem a quantidade de informação que deve ser assimilada assim como garantem uma melhor comunicação entre os desenvolvedores.

Tipos de Programação

Linguagem de máquina Assembly e o uso do assembler Linguagens de Alto Nível(Cobol, Fortran) Programação estruturada Programação orientada a objetos Programação lógica Programação funcional

Todos esses tipos de programação continuam existindo nos dias de hoje. Não devemos encarar um estilo melhor que outro ou uma língua dentro de um tipo melhor que outra, devemos sim analisar e escolher o tipo de programação e língua de acordo com o problema que estamos resolvendo.

Exercício 1.1: Pesquise sobre os paradigmas logico e funcional de programação. Descubra suas aplicações e diga como é sua aceitação no mundo industrial.

Exercício 1.2: Pesquise sobre o Assembly. Diga qual suas características e sua aplicação. Verifique os deferentes tipos de Assembly e diga quais são mais usados.

Metodologia

Uma metodologia é uma descrição das etapas que devemos seguir para alcançar um produto de alta qualidade.

Existem metodologias para os vários tipos de programação. As metodologias predominantes nos padrões inustriais atuais são RUP e uma que vem ganhando espaço, o XP.

Page 6: Composição de software orientado a objetos

A maioria dessa metodologias possuem muitos detalhes e práticas recomendadas que podem confundir um iniciante, por isso adotaremos nesse material aqui presente uma metodologia simples, que permita a criatividade em cada etapa do desenvolvimento, metodologia ripple.

Exercício 1.3: O que é RUP? Quais são suas características e quando deve ser usado.Exercício 1.4: O que é XP? Quais as vantagens dessa metodologia e porque ela vem ganhando espaço?

Introdução aos Objetos

Omitiremos o básico apostando no background do leitor. Primeiro vamos dar uma olhadinha em modelos. Modelo é a representação de

um domínio do problema ou uma definida solução que nos permite discutir e adicionar idéias ao todo. Assim como arquitetos montam um modelo antes de discutir uma construção para ter uma idéia de como o resultado será, devemos construir modelo para vislumbrar nossa aplicação. Grande parte do desenvolvimento de software envolve construir e refinar modelos. Uma classe é um protótipo para se criar um objeto, uma fábrica. Para criarmos um objeto devemos escrever a seguinte linha de código: new Pessoa(“Giovana”)

Depois de criado o objeto temos que coloca-lo em algum lugar onde possamos acha-lo mais tarde, ou seja devemos atribuir uma referencia a ele: aPessoa = new Pessoa(“Giovana”) Em um diagrama UML nome de classes não são sublinhadios enquanto de objetos sim. Nós podemos fazer a maior parte do trabalho de projeto de software usando diagrama de classes, diagramas de objetos podem ser usados para propósitos de ilustração e verificação. Nomes de classes normalmente possuem letra inicial maiúscula.

Softwares orientados a objetos são mais naturais devido a tendência humana de dividir tudo ao seu redor em classes.

Page 7: Composição de software orientado a objetos

Estrutura básica das classes

Algumas linguagens puramente orientadas a objetos possuem asserções, condições lógicas que sempre devem ser verdadeiras. Lembre-se da asserção usada no teste de unidade. As asserções podem ajudar a compar a estrutura básica de uma classe.

Diferença entre identidade e equivalência

Duas referencias podem apontar para um mesmo objeto, nesse caso dizemos que elas possuem a mesma identidade. Mas se dois objetos com diferentes identidades possuírem os mesmos atributos dizemos que eles são equivalentes. Teste de identidade ( aPessoaum == aPessoadois) Teste de equivalência aPessoaum.equals(aPessoadois) Os testes retornam booleanos e podem ser usados em várias estruturas de programação.

Fig. Representação UML de um objeto. Se tivéssemos uma classe o nome não poderia estar sublinhado e normalmente começaria com maiúscula.

Page 8: Composição de software orientado a objetos

Ao escrever o design de um objeto primeiro devemos determinar as operações que um objeto deve executar e quais atributos o objeto deve ter para garantir que essas operações sejam exeutadas. Operações são ditas métodos dos objetos.

Encapsulando objetos

Esconder seus atributos usando suas operações é encapsular um objeto. Se alterássemos diretamente esses atributos teríamos um código dependente desses atributos. Se futuramente desejássemos mudar um atributo teríamos que alterar todos códigos que fazem referencia a ele, com o encapsulamento podemos entretanto alterar apenas uma operação. Assim garantimos a reusabilidade do código bem como evitamos bugs.

Associação e agregação

Nenhum objeto é isolado. Os objetos se comunicam através de outros objetos e além disso precisam trocar informações tornando assim o sistema mais poderoso.

As duas principais formas de conectar objetos é através da associação e agreação. Associação é uma forma simples e “fraca” de se conectar objetos. Através da associação combinamos objetos de forma que eles não se tornem dependentes um dos outros. Por exemplo considere um carro e dois passageiros. Eles estão associados, vão ao mesmo destino e ocupam o mesmo volume no espaço. Mas a qualquer momento um dos passageiros podem abandonar o carro e assim a associação.

Agregação é uma conexão mais forte entre os objetos. Significa juntarmos objetos pequenos para fabricarmos um grande objeto. Geralmente um agregação combina com uma relação de objetos do mundo real parte-todo. Significa dependência pois a parte perde sua função se considerada fora do contexto do todo. Colocamos um losango branco no lado do todo para representar a agregação.Uma boa pergunta para determinarmos se devemos ter uma associação ou uma agregação portanto é nos perguntar se um objeto existe ou melhor se tem utilidade fora da “possível” agregação.

Page 9: Composição de software orientado a objetos

Amigos são uma associaçãoComponentes de uma televisão são uma agregaçãoLivros em uma biblioteca são uma associação

Exercício 1.6: Determine os seguinte casos como assosiação ou agregação:Casas em uma ruaPáginas em um livroComponentes num sistema de multimídia de uma casa

Lembrem-se da diferença entre grafos e árvores. Uma agregação se parece mais com uma árvore e uma associação com um grafo. Uma árvore é um caso especial de grafo onde cada nó pode ter apenas um nó parente e vários nós filhos. Observe que a agregação deve respeitar além dessa lei a dependência entre as classes.

Navegabilidade

As conexões entre classes vistas até aqui são chamadas de links. Há também a navegabilidade. O rótulo da navegabilidade normalmente está

ligado a um atributo que faz uma classes estar conectada a outra. Por exemplo o Objeto Consumidor tem outro Objeto Adress como atributo, podemos representar essa característica usando a navegabilidade com o rótulo adress. Observação a navegabilidade é representada pela seta. Portanto a navegabilidade só ocorre da parte para o todo, portanto a parte desconhece a existência do todo. Ou seja não há nada em sua implementação que a diz que faz parte do todo. Muitos links de navegabilidade terminam como ponteiros em linguagens orientadas a objetos. Ponteiros são os endereços de memória de um objeto.

Page 10: Composição de software orientado a objetos

Obs.: Com a intenção de ser independente de linguagem todos os exemplos aqui apresentados são ilustrativos, ou seja, você poderá não encontrar classes em Java que correspondam exatamente as usadas aqui. Portanto se você for um programador Java ou .NET tenha em mão a sua biblioteca de classes.

Mensagens

Sabemos que objetos isolados não possuem muita utilidade. Os objetos comunicam entre si através de mensagens. Exemplo de colaboração entre objetos usando UML.

Links não tem direção Nomes objetos não são sublinhado A resposta não segue o padrão UML. Abaixo estão alguns exemplos de mensagens.

Page 11: Composição de software orientado a objetos

As mensagens nem sempre recebem uma resposta ou um resultado plausível. Fazer com que as mensagens sempre recebam resultados plausíveis pode ser fundamental em casos como o computador de bordo de um avião. Existe uma área da engenharia de software chamada “software reliability” ou confiabilidade de software que lida exatamente com esses problemas. Por hora assumiremos que todas as mensagens retornam e seus resultados são válidos.

Quando um objeto recebe uma mensagem ele executa códigos, portanto uma mensagem invoca uma operação. As mensagens podem ter parametros também chamados de argumentos, um parametro é um requisito que o objeto que executa a operação precisa para realizá-la com sucesso.

Pense : Ao passar um argumento a um método pense se é possível aquele método realizar aquela operação sem aquele argumento, se é possível usarmos outra lista de argumentos e qual abordagem é mais relevante para a reusabilidade do código, ou seja, qual abordagem é “mais” OO.

Lembre-se que em java determinamos qual objeto receberá a mensagem usando um ponto, como em: aObject.message(aParameter) Podemos as vezes pensar se uma mensagem que enviamos a um objeto deve requisitar alguma informação ou mandá-lo executar um comando. Uma regra que podemos lembrar é: “Uma mensagem deve ser uma pergunta ou um comando, mas não ambos”. Se for uma pergunta a mensagem não deve alterar nenhum atributo do objeto nem de outros objetos ligados a ele. Como exemplo o tempo não pode mudar apenas porque o pedimos. Caso a mensagem mande um objeto executar uma operação então não devemos obter nenhuma resposta. Como exemplo podemos mandar um objeto sacar 100 reais de uma conta, não devemos esperar que esse objeto retorne uma resposta como o restante do dinheiro que sobrou na conta. Se quisermos obter tal resposta então devemos mandar outra mensagem perguntando qual o saldo atual da conta. Um comando altera um objeto que recebe como argumento ou o próprio objeto em que está implementado.

Pense : Seus métodos estão seguindo as regras básicas de OO?

Há casos em que vale a pena termos uma mensagem dos dois tipos É valido um objeto peguntar a si mesmo. Assim como fazemos perguntas a nós mesmos como em “O que eu fiz ontem?”

Exemplo de Colaboração

Page 12: Composição de software orientado a objetos

Temos uma interação complicada entre dois tipos de objetos, programar já é suficiente dificíl sem esse tipo de complexidade do mundo real. Temos um consumidor que dependente da interface da balconista e um vendedor que depende da interface do consumidor. Mudar um objeto significa mudar o outro também, um pesadelo para a manutenção do código.

Constratemos a comunicação entre a balconista e o consumidor com a comunicação entre um contador e a balconista. A balconista pode mandar uma

Page 13: Composição de software orientado a objetos

mensagem para o contador e esperar uma resposta mas o contador não pode perguntar nada a balconista. Assim a interação é de mão unica e os mesmos objetivos continuam sendo atingidos. Chamamos essa interação de cliente-fornecedor. Porém nesse tipo de interação temos mais chance de reusar o código e portanto chegamos a um resultado orientado a objetos.

Como funciona um programa orientado a objetos Um programa orientado a objetos instancia objetos, conecta eles e os faz colaborar mandando mensagens entre si. Mas quem faz as coisas acontecerem? Todas as linguagens orientadas a objetos possuem um ponto de entrada que no caso do Java é a função main.

Garbage Collection = Coleção de Lixo Todo objeto ocupa um espaço na memória. A medida que o programa continua sendo executada esses objetos passam a ocupar mais memória, imagine um programa rodando em um servidor por anos. Portanto devemos limpar da memória objetos que não estão mais sendo usados(garbage collection). Gerenciar o ciclo de vida de um objeto e decidir quando ele deve ser apagado da memória é uma tarefa difícil e não é incomum um programador esquecer uma etapa, tal falha é chamada de memory leak. Em Java a própria plataforma faz isso para o programador. Todo programa em java possui um assistente chamado coletor de lixo(garbage collector).

Em linguagens que não possuem essa característica é comum termos que escrever um sistema que é responsável pela “organização da casa”, tal sistema é chamado de run time system e devemos escreve-los nós próprios, tal sistema inclui um garbage collector. Superficialmente um sistema coletor funciona da seguinte forma: ele deleta qualquer objeto que não pode ser acessado, direta ou indiretamente, de qualquer nome do programa. Se um objeto não pode ser acessado ele não pode mandar nenhuma mensagem consequentemente também não pode responder a nenhuma pergunta, portanto ele deve ser lixo.

Herança/Generalização/Especialização

Page 14: Composição de software orientado a objetos

Omitirei o básico sobre esse tipo de relação de classes.

Encapsulando objetos Devemos declarar um campo como privado toda vez que ele for útil apenas para a classe em questão, da mesma forma para os métodos. Não use um método público exceto se ele for responsável pelas mensagens do objeto ou se você tiver um bom motivo para tal. Garantimos assim objetos encapsulados que operamos usando apenas sua interface(métodos) e além disso garantimos a reusabilidade e a orientação a objetos. Já que nenhum outro objeto pode alterar as varáveis do nosso objeto sem usar sua interface e usando a interface(métodos) nosso código pode ser mais facilmente estendido e facilitamos sua manutenção.

Elementos de Classe Quando queremos que uma informação não seja vinculada especificadamente a um objeto mas sim a classe podemos declarar uma variável ou método como estáticos. Em java isso equivale a inserir a keyword static na declaração desse método ou variável. Esses elementos são chamados de elementos da classe. Não é tão fácil quanto parece o uso de elementos de classe pois algumas linguagens não trata uma classe como um objeto puro, isso quer dizer que as classes não tem as mesmas características como herança, mesmo linguagens que possuem essa característica ficam a merce de complicações como metaclasses( C++). Portanto sempre antes de decidir que sobre a utilidade de um elemento de classe pense nas seguintes alterntivas:

1. Procure ou introduza um novo tipo de objeto, fique atento para não criar objetos sem sentidos só para evitar o uso elementos de classe. Por exemplo ao invés de inserir um novo elemento de classe taxaDeInvestimento podemos criar ou mesmo inserir esse campo numa classe chamada Banco e ainda ganhamos com a extensão do sistema já que o sistema pode agora conter vários tipos diferentes de bancos.

2. Use um singleton pattern. Singleton é um pattern que garante que podemos ter apenas uma instância de uma classe, o singleton object.

Page 15: Composição de software orientado a objetos

Exemplo: A pergunta “Esse é um ano bissexto?” combina perfeitamente com esse padrão já que precisamos apenas uma instância do calendário gregoriano.Uma instância onde todos os objetos podem perguntar datas.

Tipos primitivos e objetosUma linguagem orientada a objetos pura deve considerar tudo como um objeto.

Algumas linguagens também possuem tipos primitivos, existem várias justificativas para o uso desse tipos brevidade, performance e resquícios de linguagem estruturada. A maior distinção entre objetos e tipos primitivos é que podemos mandar mensagens para esses objetos primitivos ou qualquer outra característica de um objeto. Primitivos são uteis para valores simples como um inteiro ou caracteres individuais, qualquer outra coisa deve ser um objeto.

Em java arrays são algo entre um objeto e um primitivo por questões de performance mas o programador pode ser puro evitando esse tipo de primitivo e usando a classe List.

A notação UML permite usar tipos genéricos para podermos mapear o design para qualquer linguagem orientada a objetos. Por exemplo: Integer, Real, Boolean. Entretanto a convenção UML também permite usar os tipos especificos de uma linguagem desde que o pojetista sabe o que está fazendo.

Como regra sempre que possível tente usar um objeto no lugar de um tipo primitivo. Em java corresponde a usarmos “Integer a” ao invés de usarmos “int

a”.

TerminologiaUsaremos apenas os termos sublinhados

Page 16: Composição de software orientado a objetos

Nas etapas inciais do desenvolvimento tendemos a usar os termos operações e atributos e nas etapas finais tendemos a usar a terminologia métodos e campos porque esta metodologia está mais próxima da programação. Não se deixe confundir pela terminologia, caso entre em dúvida procure um dicionário online rapidamente.

Reusando Código

Objetivos: desenvolvimento rápido e simples, manutenção simples, código mais robusto(toda vez que ele é reusado achamos novos erros, eles são corrigidos, a performance é melhorada). Focar nas questões do “negócio” e não em pequenas mágicas da programação.

Porque sistemas orientandos a objetos usam conceitos de um domínio é muito mais provável que oportunidades de reuso apareceram. Por exemplo ao invés de pensarmos o que um sistema de pagamento deve esperar que uma classe empregado contenha devemos pensar o que a classe empregado significa para uma companhia.

Assim podemos usar a classe empregado em outros sistemas. Além disso a modularidade dos objetos diminui a tendência de espalhar atributos e operaçções da classe empregado pelo sistema, tornando mais simples incrementarmos nossa implementação com novas características e também correção de bugs. Hoje temos que apenas implementar as partes do código que necessitaremos apenas para nossa aplicação os demais códigos podem ser reaproveitados.

Tipos de reusabilidade:

Page 17: Composição de software orientado a objetos

1. Reutilização de funções dentro de um sistema: escrevemos funções genéricas que podem ser chamadas de qualquer parte do sistema, como por exemplo uma função para ordenar uma lista

2. Reutilização de métodos de um objeto: métodos encapsulados dentro de um objeto podem ser chamados por outros métodos dentro do mesmo objeto. Utilize essa técnica SEMPRE que possível. Normalmente métodos não públicos servem para dividir da melhor forma tarefas complexas que devem ser realizadas por um objeto.

3. Reusando classes dentro de um sistema: é o ponto principal de orientação a objetos, quando especializamos uma classe, quando agregamos duas classes estamos reaproveitando código

4. Reusando funções entre sistemas5. Reusando classes entre sistemas6. Bibliotecas de funções: exemplo stdio.h em C.7. Biblioteca de classes: exemplo J2EE Class Library, biblioteca .NET

framework. Essas bibliotecas podem possuir direitos autorias. Portanto escrever um código reusável pode render dinheiro as empresas.Podemos chegar a casos de usar componentes completos dentro de uma aplicação.

8. Design Patterns9. Frameworks: é uma estrutura pré existente onde você acopla seu código. Um

framework é constituido de classes junto com documentações que descrevem as regras de construção que devem ser seguidas pelo desenvolvedor. Exemplo: Enterprise Java Beans, Hibernate, JUnit.

Portanto como projetamos sistemas reusáveis?Primeiro aprenderemos a projetar classes reusáveis assim todas as classes conectadas a elas também serão, depois mergulharemos em tópicos mais avançados como design patterns e frameworks.

Dicas para maximizar a reusabilidade: Siga estilo de codificação padrão. Documente extensivamente

■ Nome auto explicativo■ Comentário curto resumindo a utilidade da classe■ Comentário longo de vários paragrafos explicando: Como, Onde,

Porque, Quando deve ser usada e como foi implementada.■ Descrever como mensagens publicas devem ser usadas. Lembre-se que

quem for reutilizar sua classe não poderá invocar as mensagens privadas de seu objeto.

■ Descrever o contrato entre o objeto e seus clientes, por exemplo obrigações de ambos os lados

■ Documentações separadas da classe como projeto de classes, tutorias e definição de requisitos

Prepare-se para escrever mais código, ou seja evitar atalhos lógicos que só você entenderá e encapsular sua classe.

Use padrões e frameworks. Usá-los além de diminuir seu trabalho facilita a compreensão de quem vai ler seu código.

Page 18: Composição de software orientado a objetos

Projete objetos cliente-fornecedor: se você tiver comunicação de mão dupla ou pior cíclica em seu código acaba tendo como resultado um código chamado “código espaguete”. Pense nos objetos como serventes que executam o que forem pedidos sem se preocupar com quem pediu.

Faça cada objeto com um propósito único, também conhecido como alta coesão.

Separe a interface gráfica da lógica da aplicação. Detalhes sobre esse tópico serão abordados futuramente.

Projete Objetos para responder questões e realizar operações.

Page 19: Composição de software orientado a objetos

Herança

Vantagens: Permite uma modelagem muito mais poderosa e rica. Beneficia tanto quem está

desenvolvendo código como o torna reusável. Permite definir informação e comportamento em uma classe e compartilhar É natural

Exemplo:

Observe a notação em UML para declarar um o tipos da variável e tipo dos parametros e os valores de retorno dos métodos, usa-se os dois pontos “ : “.

Outro exemplo, suponha que queiramos modelar uma coleção. Coleções são objetos que contem outros objetos.

Tipos: Listas: Coleção de objetos que os mantém na ordem que foram inseridosBag: Não mantém os objetos na ordem.LinkedListArrayList

Objetivo: Colocar todas essas classes como uma herança de Collection.Quando estivermos montando uma hierarquia quanto mais perto da base

colocarmos uma mensagem melhor. Normalmente nós tendemos a primeiro buscar as mensagens que um objeto deve ter depois seus atributos isso é natural já que as mensagens são sua interface com o mundo externo

1.Decidir onde cada classe se encaixa na hierarquiaTodas classes são coleções então natural colocarmos Collection na baseNotamos que todas as classes mantém suas coleções ordenadas exceto Bag

portanto Bag deve estar abaixo de Collection e separada das demais classes. Fica claro também que ArrayList e LinkedList são tipos de List.

Page 20: Composição de software orientado a objetos

2. Depois procuramos mensagens que podemos compartilhar entre as classesMensagens candidatas:

contains(:Object):BooleannumberOfElements():intelementAt(:Int):Object

Quanto mais perto da base colocarmos o método melhor.

A mensagem elementAt(:Int):Object só faz sentido para listas ordenadasMas para cada lista ordenada teremos uma implementação diferente desse

método.

Pense que iremos implementar o método contains. Chegamos a conclusão de que o método contains não pode ser escrito na classe Collection já que sua implementação será diferente em listas ordenadas e não ordenadas.

Implementação para List

1 boolean contains(Object o) {2 for (int i = 0; i < numberOfElements(); ++i) {3 if (elementAt(i) == o) {4 return true;5 }6 }7 return false;8 }

Chegamos ao real benefício da herança, agora podemos chamar a mensagen contains em qualquer direção da herança sem nos preocupar com sua implementação.

Page 21: Composição de software orientado a objetos

Com relação a implementação de numberOfElements():int, pensemos:Abordagem 1) Guardar o número de posições como um campo de instânciaAbordagem 2) Usar uma operação para calcular o número de Objetos

Esse tipo de problema sempre surge e temos que decidir entre espaço e tempo. Nunca podemos escolher precipitadamente uma abordagem, pois nenhuma abordagem sempre será útil em todos os casos. No nosso exemplo preferimos usar a abordagem número 2.

As mensagens que não possuem o método implementado estão em itálico, são os chamados métodos abstratos. Já aquelas que efetivamente possuem a implementação são chamados métodos concretos. Em UML voce pode representar o método abstrato usando o itálico ou a palavra {abstract} em frente ao método.

Classes abstratas

Page 22: Composição de software orientado a objetos

Classes abstratas são aquelas que possuem pelo menos um método abstrato, seja ele introduzido pela própria classe ou herdado.

As mesmas notações UML valem para as mensagens e nome das classes.Vantagens:

Permite modelagem muito mais rica e flexível, por exemplo nossa classe List possuem as três mensagens independente se podemos ou não implementar o método.

Permite maior compartilhamento de código

Exemplo: Considere uma fruta e sua casca. Caso queiramos descascar a fruta sabemos que podemos fazê-lo com qualquer fruta mas não podemos descrever como fazer isso pois para cada fruta teremos um processo diferente. Essa operação deve ser abstrata e o conceito de fruta também o é.

Se tivéssemos que dizer a uma fruta para ela se descascar ? Como saberia como executar a operação se não temos sua implementação para a fruta?

A maioria das linguagens orientadas a objetos evita isso impedindo o programador de instanciar uma classe abstrata.

Isso é natural, se te desse dinheiro para ir ao mercado comprar uma fruta, você me perguntaria qual fruta você deseja que eu compre? Porque você precisa de um pedido concreto.

Quando você for montar uma hierarquia de classes deve ter em mente que a maioria das super classes são abstratas. Isso decorre do fato que a herança é uma generalização de baixo para cima:

1.Nós olhamos conceitos concretos que existem no domínio do nosso problema e pensamos sobre seu comportamento e conhecimento.

2. Buscamos semelhanças entre classes concretas para chegarmos a superclasses3.Agrupamos superclasses em mais superclasses até atingirmos nossa classe

mais generalista.

Quando chegamos a superclasses devemos pensar que elas são abstratos exceto se elas representarem conceitos concretos na etapa 1.

É tão natural que uma superclasse seja abstrata que Java e UML nos permite marcar uma classe como abstrata mesmo se não tivermos nenhum método abstrato ainda.

Portanto se você observar uma classe concreta herdando outra classe concretapense nas seguintes transformações.

1.

Imagine que X fosse fruta e Y uma laranja. Esperaríamos que uma laranja trabalhasse exatamente como uma fruta, mas com informações extras e comportamento extra.

Page 23: Composição de software orientado a objetos

Motivos para se redefinir métodos1.Implementar um método abstrato2.Estender as funcionalidades do método herdado

3.Implementar novamente um algorítimo de forma mais eficiente para determinada subclasse.

Implementando um Stack

Imagine uma pilha de pratos. Uma stack é uma estrutura de dados parecida, podemos: adcionar um elemnto a pilha(push( ) ); retornar um objeto no topo da pilha (peek ( ) ); retornar verdadeiro se a pilha estiver vazia ( isEmpty( ) ); remover um objeto do topo da pilha ( pop( ) );

Como escrever software orientados a objetos envolve reusabilidade do código, pensemos em como reaproveitar uma classe que já existe, nesse caso a classe LinkedList, para aproveitarmos o código devemos ter uma herança ou uma composição.

Uma composição é uma agregação de objetos extremamente forte.

Agregação e composição

A associação tem duas formas particulares: a agregação e a composição. As duas são muito parecidas, elas relacionam um objeto composto com suas partes. Por exemplo, a associação entre uma universidade e seus departamentos é uma agregação, a associação entre um carro e suas partes é uma composição. A diferença entre os dois é que a composição é mais ``física'', com a composição, uma parte não pode pertencer a dois objetos compostos ao mesmo tempo (um motor não pode pertencer a dois carros ao mesmo tempo), e uma parte não pode existir sem o objeto composto (mas o composto pode ``sobre-viver'' às suas partes).

Agregação e composicão aceitam multiplicidade, só do lado das partes para a composição (um carro é composto de quatro rodas) e dos dois lados com a agregação (uma palavra pode pertencer a várias frases e uma frase possui várias palavras).

Page 24: Composição de software orientado a objetos

Geralmente, a composição implica uma forma de propagação de algumas propriedades. Por exemplo, quando o objeto composto morrer, as partes morrem também (definição da composição), ou quando um carro se mover, as partes se movem também. Essas propagação não é a herança, ela não é automática, você tem que especificá-la e implementá-la. Todas as propriedades não são propagadas, por exemplo, um carro pode ser vermelho e o motor não.

Herança versus Composição

Vantagens únicas da herança

Natural/Elegante/Permite escrever código genérico

Desvantagens da herançaDifícil fazer bem/Difícil mudar quando descobrimos deficiências em

nosso design/É mais difícil para programas clientes entenderem/ Mais difícil mudá-lo também

Composição atinge os mesmo objetivos que a herança com as vantagens:

Simples de produzir/Fácil de mudar/ Fácil de entender para os clientes/ Não deixa a desejar no código pelo lado do cliente.

Herança é uma relação do tipo “é um”

Agregação é uma relação do tipo “tem um”

A frase “Carro possui pneus” apresenta agrega¸c˜ao entre carro epneu. Por´em, “Ferrari ´e um tipo de Carro” apresenta heran¸ca.

Page 25: Composição de software orientado a objetos

Princípio da substituição de Liskov

Page 26: Composição de software orientado a objetos
Page 27: Composição de software orientado a objetos

Padrões de Interfaces

Introdução as Interfaces Adapter

Adapta uma interface de uma classe para atender as expectativas de um cliente

FacadeFornece uma simples interface em um coleção de classes.

CompositeDefine uma interface que se aplica a objetos individuais e grupos de objetos.

BridgeDesacopla uma abstração de sua implementação assim elas podem variar independentemente.

Page 28: Composição de software orientado a objetos

Introdução as interfaces

O que é?Conjunto de campos e métodos que uma classe permite que a outra acesse. Em

Java esse conceito é elevado no sentido de se tornar uma construção separada entre implementação e interface. Assim várias classes podem ser atreladas a mesma interface ou uma classe pode implementar mais de uma interface.

Muitas vezes sua intenção no design vai além do simples conceito de interface. Nesse contexto que surgem os padrões de interface. Eles estendem além o conceito de interface para atingir objetivos do designer.

Atividade: Cite diferenças entre classe abstrata e interfaces em JAVA.

Exemplo:

interface Act {  void act();}

class Actor1 implements Act {  public void act() {    System.out.println("To be, or not to be");  }}

class Actor2 implements Act {  public void act() {    System.out.println("Wherefore art thou Romeo?");  }}

public class TryOut {  public static void main(String args[]) {    Actor1 hamlet = new Actor1();    Actor2 juliet = new Actor2();    tryout(hamlet);    tryout(juliet);  }

  private static void tryout(Act actor) {    actor.act();  }}

Diferença entre o uso de classes abstratas e interfaces

Uma classe abstrata sem nenhum método não abstrato tem um funcionamento parecido com o de uma interface. Mas há diferenças, observe:

1. Uma classe pode implementas quantas interfaces quiser mas pode ser subclasse de apenas uma classe abstrata

2. Todos métodos da interface são abstratos, seja eles declarados explicitamente ou não.

3. Uma interface não pode conte campos de instância apenas constantes.4. Uma classe abstrata pode ser publica, protected, private, ou nenhuma. Já uma

interface pode ser apenas publica ou nenhuma(visível a package).

Page 29: Composição de software orientado a objetos

5. Todos métodos em uma interface devem ser públicos enquanto em uma classe abstrata eles podem ser protected, private ou nenhum.

6. Uma classe abstrata herda de Object e portanto possiu vários métodos como clone() ou equals()

Obs.: Interfaces sem métodos podem são chamadas de interfaces de marcação. Uma aplicação útil é o caso de um método na hierarquia de classe não ser útil a todo tipo de subclasse. Por exemplo o método Object.clone(). Assim voce pode criar uma interface de marcação para obrigar as subclasses a optar pelo método caso queira usá-lo assim o método clone() exige que toda classe que o execute possua a implementação de uma interface de marcação, como no nosso caso Clonable.

Interfaces e obrigações

Todas as classes que implementarem a interface devem respeitar o nome do método e os comentários sobre ele. Esses dois itens estabelecem o que chamamos de contrato.

Algumas vezes os métodos da interface não exigem em seu contrato que sejam implementados por todos objetos assim podemos deixar seu corpo vazio na classe que o implemente. Ou seja, esse objeto não necessariamente reagira diante determinada chamada de outro objeto. Essa técnica é usada quando desejamos registrar para obter notificações, nesse caso o objeto deve tomar alguma atitude quando o método é chamado mas geralmente não está oferecendo um serviço ao objeto que chamou o método.

Exemplo: A classe que implemente MouseMotionListener interface de java.awt.event deverá implementar os métodos mouseDragged(MouseEvent e) e mouseMoved(MouseEvent e). A presença desses métodos não significa que o objeto deve tomar uma atitude quando o método for chamado. De fato seria natural reagir a um drag and drop e não a um movimento do mouse.

Se voce planeja criar uma interface que possua muitos métodos notificadores é interessante que crie também um stub. Um stub é uma classe que implementa uma interface com métodos que não fazem nada. A partir do stub podemos criar uma hierarquia de classes, sobrescrevendo apenas os métodos da interface que sejam importantes para a nossa aplicação.

Exemplo: WindowsApadter

Page 30: Composição de software orientado a objetos

AdapterComo programador escrevemos nossas classes e nossas interfaces portanto nos

escrevemos os contratos aos quais nossas classes devem obdecer. Mas nem sempre voce poderá fazer tal.

Quando voce precisa implementar uma interface voce verá que existirá uma classe que fornece os serviços que o cliente precisa mas com nomes dos métodos diferentes. Voce pode usar a classe existente para atingir as necessidades dos clientes usando o Adapter pattern.

A intenção desse padrão é fornecer uma interface que um cliente espera usando os serviços de uma classe que implementa outra interace.

1. Um cliente numa package precisa chamar um método service () através da interface.

2. Existe uma classe que possui o método usefulMethod que possui a mesma função que o método service()

3. Sua missão é escreve uma classe que herda a classe ExistingClass e que implementa a interface ThoughtfulInterface

4. Depois você deve sobrescrever o método service() para que ele chame o método usefulMethod()

Arquitetura de software

Definição

Não há definição padrão, universalmente aceita, para arquitetura de software. [Software Architecture in Practice (2nd edition), (Bass, Clements, Kazman; Addison-Wesley 2003]

Page 31: Composição de software orientado a objetos

“Conjunto de decisões sobre a organização de um sistema computacional. Escolha de quais elementos irão compor o sistema, qual a responsabilidade de cada um e qual a interação entre eles.”

Propriedades visíveis. Exemplo propriedade da camada de persistência

A arquitetura não leva em consideração propriedades que não podem ser visíveis. Ex. Tipo de BD

Importância da arquitetura de software.“Dividir para conquistar” Permite que várias pessoas trabalhem num projeto

complexo e em componentes diferentes sabendo apenas um pouco sobre outros componentes. Portanto transcende as barreiras geográficas e temporais com relação ao desenvolvimento de software.

Exemplo de arquitetura

Regras que valem para todas as camadasA interação entre as camadas ocorrem através de interfacesA criação de objetos de uma camada diferente utiliza o padrão factory

diagrama de componentesusando UML 2.0

diagramas de componentes são úteis para modelar arquitetura de um sistema. Esses diagramas mostram ao organização de um sistema de código fonte bibliotecas tabelas de bancos de dados. Um componente isca do sistema. O UML reconhece cinco estereótipos de componente: executavel, biblioteca, tabela, document,arquivo.ano