Polimorfismo e Acoplamento Dinâmico Adriano J. Holanda 15/5/2015
Polimorfismo Substituição ou redefinição de atributos e métodos da superclasse para adequação às características da subclasse. Métodos: Sobrecarga (overload) fornecer mais de um método com o mesmo nome, mas com diferentes assinaturas para distinguí-los; Sobrescrita (overriding) substitui a implementação daquele método com a sua própria. As assinaturas podem ser idênticas, mas o tipo de retorno pode variar de maneira particular.
Sobrecarga Redefinição O acomplamento do método é feito de acordo com a sua assinatura. Triangulo desenhar() desenhar(ct : TipoTriangulo) apagar() 1 class Triangulo { 2 enum TipoTriangulo{isosceles, retangulo}; 3 4 void desenhar() { 5 System.out. println (Triangulo.desenhar ()); 6 } 7 void desenhar(tipotriangulo ct) { 8 System.out. println (ct ); 9 } 10 void apagar() { 11 System.out. println (Triangulo.apagar ()); 12 } }
Sobrescrita Overrinding desenhar() apagar() Forma Retangulo desenhar() apagar() Circulo desenhar() apagar() Triangulo desenhar() apagar()
Sobrecarga Exemplo 1 2 class Forma { 3 void desenhar() { } 4 void apagar() { } 5 } 6 7 class Circulo extends Forma { 8 void desenhar() { 9 System.out. println ( Circulo.desenhar() ); 10 } 11 void apagar() { 12 System.out. println ( Circulo.apagar() ); 13 } 14 }
Sobrecarga Exemplo 1 2 class Forma { 3 void desenhar() { } 4 void apagar() { } 5 } 6 7 class Quadrado extends Forma { 8 void desenhar() { 9 System.out. println ( Quadrado.desenhar() ); 10 } 11 void apagar() { 12 System.out. println ( Quadrado.apagar() ); 13 } 14 }
Sobrecarga Exemplo 1 class Forma { 2 void desenhar() { } 3 void apagar() { } 4 } 5 6 class Triangulo extends Forma { 7 void desenhar() { 8 System.out. println ( Triangulo.desenhar() ); 9 } 10 void apagar() { 11 System.out. println ( Triangulo.apagar() ); 12 } 13 }
Acoplamento Dinâmico Dynamic binding No acoplamento dinâmico (dynamic binding), o método a ser executado é vinculado à referência ao objeto durante a execução do código de acordo com o tipo do objeto no momento da execução. 1 public class PoliMain { 2 public static Forma sortearforma () { 3 switch( (int)(math.random() * 3) ) { 4 default: 5 case 0: return new Circulo(); 6 case 1: return new Retangulo(); 7 case 2: return new Triangulo(); 8 } 9 } 10 public static void main(string[] args) { 11 Forma[] fs = new Forma[9]; 12 13 for(int i=0; i< fs.length; i++) 14 fs [ i ] = sortearforma( ); 15 16 for(int i=0; i<fs.length; i++) 17 fs [ i ]. desenhar();
Acoplamento dinâmico Visualização Circulo sorteio:0 Forma@ref0 Forma@ref1 Forma@ref2 Forma@ref3 Forma@ref4 Forma@ref5 Forma@ref6 Forma@ref7 Forma@ref8
Acoplamento dinâmico Visualização Circulo sorteio: 2 Triangulo Forma@ref0 Forma@ref1 Forma@ref2 Forma@ref3 Forma@ref4 Forma@ref5 Forma@ref6 Forma@ref7 Forma@ref8
Acoplamento dinâmico Visualização Circulo sorteio: 1 Triangulo Forma@ref0 Forma@ref1 Forma@ref2 Forma@ref3 Forma@ref4 Forma@ref5 Forma@ref6 Forma@ref7 Forma@ref8 Retangulo
Acoplamento dinâmico Visualização Circulo sorteio: 2 Triangulo Forma@ref0 Forma@ref1 Forma@ref2 Forma@ref3 Forma@ref4 Forma@ref5 Forma@ref6 Forma@ref7 Forma@ref8 Retangulo Triangulo Triangulo Circulo Retangulo Circulo Triangulo
Coerção Cast Coerção é a tentativa de modificar o tipo do objeto de acordo com comportamento requerido durante a execução. 1 class Triangulo extends Forma { 2 void desenhar() { 3 System.out. println ( Triangulo.desenhar() ); } 4 void apagar() { 5 System.out. println ( Triangulo.apagar() ); } 6 void somarangulos() { 7 System.out. println (Soma angulos internos =180); } 8 } 9 public class CoercaoMain { 10 public static void main(string[ ] args) { 11 Forma[ ] fs = { new Forma(), 12 new Triangulo() }; 13 14 fs [0]. desenhar(); 15 fs [1]. apagar(); 16 /* mas fs [0] não é triangulo?!!! */ 17 ( (Triangulo) fs [1] ). somarangulos(); 18 ( (Triangulo) fs [0] ). somarangulos();
Coerção Visualização Forma Forma@ref0 Forma@ref1 desenhar() apagar() Triangulo desenhar() apagar() somarangulos()
Coerção Visualização Não é Triangulo Forma Forma@ref0 Forma@ref1 desenhar() apagar() Triangulo desenhar() apagar() somarangulos()
Coerção Segura instanceof 1 public class CoercaoSeguraMain { 2 public static void main(string[] args) { 3 Forma[] fs = { new Forma(), new Triangulo() }; 4 5 fs [0]. desenhar(); 6 fs [1]. apagar(); 7 8 if ( fs [1] instanceof Triangulo ) 9 ( (Triangulo) fs [1] ). somarangulos(); 10 11 if ( fs [0] instanceof Triangulo ) 12 ( (Triangulo) fs [0] ). somarangulos(); 13 } 14 }
Polimorfismo e Acoplamento Dinâmico Conclusões Vantagens Flexibilidade; Incorporação das técnicas de herança à linguagem. Desvantagens Perda de performance devido ao uso da memória heap; Aumenta a necessidade de checagem de condições de erro durante a execução que eram verificadas em tempo de compilação por compiladores de linguagens estáticas.
Referências Bruce Eckel. Thinking in Java. Prentice-Hall, 1998. Ken Arnold, James Gosling, David Holmes. A Linguagem de Programação Java. 4 a edição, Bookman, 2007,
Tipos Genéricos Adriano J. Holanda 15/5/2015
Antes dos genéricos Todas as classes herdam por padrão os atributos e métodos da classe Object; Uso da classe Object para lidar com a manipulação de tipos de objetos não conhecidos em tempo de compilação.
Exemplo do uso de Object // Generalização através da referência de tipo Object. 1 class No { 2 Object val; // valor 3 No prox; // proximo no 4 No(Object val, No prox) { 5 this.val = val; 6 this.prox = prox; 7 }} 8 public class ListaEncadeadaObj { 9 public No prim; // primeiro no 10 private No ult; // ultimo no 11 public void inserir (Object val) { 12 if (prim == null) { 13 ult = new No(null, null); 14 prim = new No(val, null); 15 } else { 16 No tmp = new No(val, null); 17 if (prim.prox == null) 18 prim.prox = tmp; 19 else 20 ult.prox = tmp; 21 ult = tmp; 22 }}}
Coerção da referência de tipo Object // Coerção da referência genérica para o tipo desejado. 1 public class ListaEncadeadaObjExec { 2 public static void main(exec[] args) { 3 ListaEncadeadaObj lista = new ListaEncadeadaObj(); 4 lista. inserir ( uno ); 5 lista. inserir ( dos ); 6 lista. inserir ( tres ); 7 8 No no = lista.prim; 9 while(no!= null) { 10 System.out.print( > +(String)no.val); 11 no = no.prox; 12 } 13 System.out.println(); 14 } 15 }
Problemas com a coerção // Erro na coerção da referência Object 1 public class ListaEncadeadaObjNoExec { 2 public static void main(string[] args) { 3 ListaEncadeadaObj lista = new ListaEncadeadaObj(); 4 lista. inserir (new String( uno )); 5 lista. inserir (new Integer(2)); // < ERRO EXECUCAO 6 lista. inserir (new String( tres )); 7 8 No no = lista.prim; 9 while(no!= null) { 10 System.out.print( > +(String)no.val); 11 no = no.prox; 12 } 13 System.out.println(); 14 } 15 } O operador instanceof poderia ser utilizado, mas haja testes se o código for muito extenso!
Depois dos genéricos O tipos de de dados a serem atribuídos a uma declaração são parametrizados, permitido verificação do tipo suportado em tempo de compilação.
Genéricos // Generalização da lista encadeada. 1 class No<T> { 2 T val; // valor 3 No<T> prox; // proximo no 4 No(T val, No prox) { 5 this.val = val; 6 this.prox = prox; 7 }} 8 public class ListaEncadeadaGen<T> { 9 public No<T>prim; // primeiro no 10 private No<T>ult; // ultimo no 11 public void inserir (T val) { 12 if (prim == null) { 13 ult = new No<T>(null, null); 14 prim = new No<T>(val, null); 15 } else { 16 No tmp = new No<T>(val, null); 17 if (prim.prox == null) 18 prim.prox = tmp; 19 else 20 ult.prox = tmp; 21 ult = tmp; 22 }}}
Exemplo // Declaração e utilização de tipos genéricos 1 public class ListaEncadeadaGenExec { 2 public static void main(string[] args) { 3 ListaEncadeadaGen<String>lista = 4 new ListaEncadeadaGen<String>(); 5 lista. inserir ( uno ); 6 lista. inserir ( dos ); 7 lista. inserir ( tres ); 8 9 No no = lista.prim; 10 while(no!= null) { 11 System.out.print( > +no.val); 12 no = no.prox; 13 } 14 System.out.println(); 15 } 16 }
Avaliação do tipo de dados // A avaliação do tipo de dados é feita durante a compilação. 1 public class ListaEncadeadaGenNoComp { 2 public static void main(string[] args) { 3 ListaEncadeadaGen<String>lista = 4 new ListaEncadeadaGen<String>(); 5 lista. inserir (new String( uno )); 6 lista. inserir (new Integer(2)); // < ERRO COMPILACAO 7 lista. inserir (new String( tres )); 8 9 No no = lista.prim; 10 while(no!= null) { 11 System.out.print( > +no.val); 12 no = no.prox; 13 } 14 System.out.println(); 15 } 16 }
Subtipos e curingas Trabalhar com tipos genéricos exige um pouco mais planejamento para tirar o máximo proveito da flexibilidade oferecida pela parametrização. A utilização de herança dos tipos parametrizados permite-nos reutilizar restrições e métodos dos tipos herdados.
Exemplo sem uso de curinga 1 import java. util. List ; 2 public class SubtipoCuringaNo { 3 static double somar(list<number> lista) { 4 double soma = 0.0; 5 for (Number n: lista) 6 soma += n.doublevalue(); 7 return soma; 8 }} /* Number é um subtipo de Integer mas List<Integer> não é um subtipo de List<Number>. */ 1 import java. util. List ; 2 import java. util.arraylist; 3 public class SubtipoCuringaNoComp { 4 public static void main(string[] args) { 5 List<Integer> lista = new ArrayList<Integer>(); 6 lista.add(1); 7 lista.add(2); 8 lista.add(4); 9 SubtipoCuringaNo.somar(lista); // NAO COMPILA 10 }}
Solução: uso de subtipo e curinga 1 import java. util. List ; 2 public class SubtipoCuringa { 3 static double somar(list<? extends Number> lista) { 4 double soma = 0.0; 5 for (Number n: lista) 6 soma += n.doublevalue(); 7 return soma; 8 }} 1 import java. util. List ; 2 import java. util.arraylist; 3 public class SubtipoCuringaExec { 4 public static void main(string[] args) { 5 double res; 6 List<Integer> lista = new ArrayList<Integer>(); 7 lista.add(1); 8 lista.add(2); 9 lista.add(4); 10 res = SubtipoCuringa.somar(lista); 11 System.out.println( A soma e igual a +res); 12 }}
Diagrama de herança Os curingas são fundamentais para a extensão do tipos genéricos. List<?> List<Object> List<? extends Number> List<? extends Integer> List<Number> List<Integer>
Referência
Modularização Adriano J. Holanda 15/5/2015
Modularização David L. Parnas, 1972
Módulos Módulos são componentes de software reutilizáveis que obedecem a alguns princípios de projeto [Elliot, 2014]: Especialização: cada módulo possui uma função específica. Independência: módulos devem se relacionar diretamente o menos possível com outros módulos (baixo acoplamento). Decomposição: deve ser simples testar e usar um módulo sem a necessidade de outros módulos. Substituição: um módulo pode ser substituído por outro com a mesma função.
Módulos Módulos são componentes de software reutilizáveis que obedecem a alguns princípios de projeto [Elliot, 2014]: Especialização: cada módulo possui uma função específica. Independência: módulos devem se relacionar diretamente o menos possível com outros módulos (baixo acoplamento). Decomposição: deve ser simples testar e usar um módulo sem a necessidade de outros módulos. Substituição: um módulo pode ser substituído por outro com a mesma função.
Módulos Módulos são componentes de software reutilizáveis que obedecem a alguns princípios de projeto [Elliot, 2014]: Especialização: cada módulo possui uma função específica. Independência: módulos devem se relacionar diretamente o menos possível com outros módulos (baixo acoplamento). Decomposição: deve ser simples testar e usar um módulo sem a necessidade de outros módulos. Substituição: um módulo pode ser substituído por outro com a mesma função.
Módulos Módulos são componentes de software reutilizáveis que obedecem a alguns princípios de projeto [Elliot, 2014]: Especialização: cada módulo possui uma função específica. Independência: módulos devem se relacionar diretamente o menos possível com outros módulos (baixo acoplamento). Decomposição: deve ser simples testar e usar um módulo sem a necessidade de outros módulos. Substituição: um módulo pode ser substituído por outro com a mesma função.
Modularização Modularização é uma das chaves para o sucesso de um projeto de software. Fundamental para a organização da complexidade do projeto.
Modularização Modularização é uma das chaves para o sucesso de um projeto de software. Fundamental para a organização da complexidade do projeto.
Modularização Exemplo: Biblioteca C padrão Alguns arquivos de cabeçalho da biblioteca C padrão errno.h math.h stdio.h stdlib.h string.h time.h complex.h assert.h limits.h stdbool.h...
Modularização Exemplo: Arquitetura do Sistema Operacional Android
Interfaces Modularização Interfaces são uma das primeiras ferramentas para o projeto de software modular. Elas definem um contrato no qual a implementação deve preencher. Os métodos após publicados não deveriam ser modificados, para não ocasionar quebra de contrato. Programe para uma interface, não para uma implementação [Gamma, 2005].
Interfaces Modularização Interfaces são uma das primeiras ferramentas para o projeto de software modular. Elas definem um contrato no qual a implementação deve preencher. Os métodos após publicados não deveriam ser modificados, para não ocasionar quebra de contrato. Programe para uma interface, não para uma implementação [Gamma, 2005].
Interfaces Modularização Interfaces são uma das primeiras ferramentas para o projeto de software modular. Elas definem um contrato no qual a implementação deve preencher. Os métodos após publicados não deveriam ser modificados, para não ocasionar quebra de contrato. Programe para uma interface, não para uma implementação [Gamma, 2005].
Exemplo: Biblioteca padrão C Protótipos Interface Os protótipos da especificação ANSI C permite que bibliotecas implementadas por diferentes programadores tenham aproximadamente o mesmo comportamento. 1 /* stdio.h */ 2 /*... */ 3 4 extern int fprintf (FILE * restrict stream, 5 const char * restrict format,...); 6 extern FILE *fopen (const char * restrict filename, 7 const char * restrict modes); 8 extern int fclose (FILE * stream); 9 10 /*... */
java io Exemplo: Kit de desenvolvimento Java Interfaces <<interface>> DataInput readboolean() : boolean readbyte() : byte readchar() : char readdouble() : double readfloat() : float readfully(b : byte[]) : void readfully(b : byte[], off : int, len : int) : void readint() : int readline() : String readlong() : long readshort() : short readunsignedbyte() : int readunsignedshort() : int readutf() : String skipbytes(n : int) : int Implementações do JDK devem obedecer as interfaces, pois as classes as implementam. Exemplo: JDK Oracle; OpenJDK; GNU Compiler for Java.
Modularização Declaração 1 // C++ 2 namespace foo { 3 char func(char); 4 class String {... }; 5 } 1 /// C# 2 namespace foo { 3 class String {... } 4 } 1 /* Java */ 2 package foo; 3 4 public class String {... }
Modularização Modelagem e implementação Durante a modelagem e implementação, na composição do módulo favoreça composição de objetos sobre herança de classes [Gamma, 2005].
Referências Eric Elliott. Programming JavaScript Applications O Reilly Media, 2014. Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides. Padrões de Projeto - Soluções Reutilizáveis de Software Orientado a Objetos Bookman, 2005.