Aula 24
Programação Modular, POO e
Padrões de Projeto
Alessandro Garcia Alessandro Garcia LES/DI/PUC-Rio Junho 2010Diferenças entre...
•
Módulos (em C) e Classes (Linguagens OO)
– Classes possuem um operador de instanciação explícito
– Hierarquia de classes
– Uso de herança para reuso de estrutura e comportamento
• C: reuso somente através de chamadas de funções
• Suporte direto a funções polimórficas (polimorfismo)
– Destruição de objetos (desalocação de memória) em algumas linguagens OO é feita de forma automática
Interfaces (em Java)
•
Interfaces
– As interfaces definem assinaturasde conjuntos de métodos, mas não os implementam
• tem o papel do módulo de declaração (*.h)
• ... mas permite definir interfaces reutilizáveis (p.e. serializable)
– Interface é uma especificaçãoque permite que classes, não diretamente relacionadas na mesma hierarquia, possam incorporar propriedades similares
– Uma classe que implementea interface deve implementar TODOSos métodos definidos nesta
Nov 2009 Alessandro Garcia © LES/DI/PUC-Rio 3 / 27
– public interface Sleeper {
public void wakeUp();
public long ONE_SECOND = 1000; // milli }
Diferenças entre...
•
Módulos (em C) e Classes (Linguagens OO)
– Classes possuem um operador de instanciação explícito
– Hierarquia de classes
– Uso de herança para reuso de estrutura e comportamento
• C: reuso somente através de chamadas de funções
– Destruição de objetos (desalocação de memória) em algumas linguagens OO é feita de forma automática
– Suporte direto a definição de interfaces...
– Linguagens OO: melhor controle de visibilidade (graus de en p l mento)
Nov 2009 Alessandro Garcia © LES/DI/PUC-Rio 4 / 27 encapsulamento)
Visibilidade de membros da classe
Controlando o acesso aos membros da classe
Especificador classe subclasse pacote todos
private X
protected X X X
public X X X X
Nov 2009 Alessandro Garcia © LES/DI/PUC-Rio 5 / 27
public X X X X
default
X X
Pacotes (em Java)
•
Pacotes
– Para facilitar o uso, controle de acesso e controle de conflito de nomes, os programadores agrupam classes e interfaces
l i d t
relacionadas em pacotes
– Para definir qual pacote uma classe pertence, basta incluir no início arquivo da classe a linha:
package nomePacote;
– Os pacotes necessários a uma classeOs pacotes necessários a uma classedevem ser incorporados devem ser incorporados através do comando import
Abstract e Final
•
Métodos Abstract
: não possuem implementação e devem
ser implementados pelas subclasses
– classe deve ser definida como “abstract” quando possuir pelo menos um método abstrato
menos um método abstrato
•
Métodos Final
: não podem ser sobrescritos
– é válido estender uma classe não marcada como final
• mas não podemos sobrescrever seus métodos final
Nov 2009 Alessandro Garcia © LES/DI/PUC-Rio 7 / 27 Erro de compilação
Membros estáticos de uma classe
•
Métodos e variáveis estáticos
– Declarados com o especificador static
– São comuns a todos os objetos da classe Utili d d l ã d t t
– Utilizados para declaração de constantes
– Utilizados para declaração de métodos que não necessitam de uma instância da classe
static int FALSO 0; static int VERDADEIRO 1;
public static boolean testa( int p ) {
Nov 2009 Alessandro Garcia © LES/DI/PUC-Rio 8 / 27 public static boolean testa( int p ) {
if( p == this.VERDADEIRO ) return( true );
else
return( false ); }
Diferenças entre...
•
Módulos (em C) e Classes (Linguagens OO)
– Classes possuem um operador de instanciação explícito
– Hierarquia de classes
– Uso de herança para reuso de estrutura e comportamento
• C: reuso somente através de chamadas de funções
– Destruição de objetos (desalocação de memória) em algumas linguagens OO é feita de forma automática
– Suporte direto a definição de interfaces...
– Linguagens OO: melhor controle de visibilidade (graus de en p l mento)
Nov 2009 Alessandro Garcia © LES/DI/PUC-Rio 9 / 27 encapsulamento)
• exemplo: Java...
– Suporte direto à funções polimórficas
• É possível a implementação de funções polimórficas em C?
Polimorfismo em C? Função como um dado
•
Uma
função definida
é uma
seqüência de bytes
contida em
um espaço de dados
• usualmente contíguo
• em geral, não alterável g , constante – possui um nome
• usualmente o nome da função
– possui um endereço • origem de execução Tamanho Endereço do Meio nome da função
– possui também um tipo...
Espaço de dados Endereço do
espaço Função de acesso(
Função como um dado
•
O
tipo de uma função
é estabelecido pela sua
assinatura
física
– valor retornado
– lista dos tipos de parâmetros
• os nomes dos parâmetros não fazem parte da assinatura
• o nome da função não faz parte da assinatura
– exemplo: int ( int , double )
•
Uma função A será do
mesmo tipo
que a função B caso
b t
h
i
t
Maio 2009 Alessandro Garcia © LES/DI/PUC-Rio 11 / 32
ambas tenham a mesma assinatura
– programador deve garantir que exista uma “igualdade” semântica
Dado tipo ponteiro para função
•
Em C e C++ podem ser definidas variáveis do tipo ponteiro
para função
– exemplo: int (* VarF1 )( int , double )
• VarF1 é um ponteiro para função do tipo: int ( int , double )
– Exemplo de atribuição
int Func( int X , double Y ) {
...
Func é uma constantedo tipo
ponteiro para uma função do tipo: int ( int , double )
Maio 2009 Alessandro Garcia © LES/DI/PUC-Rio 12 / 32 } /* Func */
main(...) { VarF1 = Func ; }
Exemplo simples: integração por trapézio
•
Seja f(x) uma função contínua em [a, b]
– o problema da integração numérica consiste em calcular um valor aproximado para
solução: calcular a integral
bdx x f I ( )
– solução: calcular a integral
“aproximada” através da regra dos trapézios
a
f( )
função a ser integrada
Exemplo: f(x) = 2 * x
double
Y
limite superior limite i f i
m m m
TR h f f f f f f f I 02 1 2 3 2 1 2 Maio 2009 Alessandro Garcia © LES/DI/PUC-Rio 13 / 32
A B X 0 1 2 3 4 5 6 7 8 limite superior inferior f0 f1f1 f2f2 f3f3 fm Parâmetros: - número de interações: 8 - limites inferior e superior: 0 e m -e a própria função f
Exemplo simples: integração
/* Função de integração numérica utilizando regra dos trapézios */ double Integrar( double LimInf ,
double LimSup , int NumInt ,
double ( * Func )( double X )) { { double Integral = 0.0 ; double Intervalo ; int i ; assert( NumInt >= 2 ) ;
Intervalo = ( LimSup - LimInf ) / ( NumInt - 1 ) ; Integral += Func( LimSup ) ; Integral += Func( LimInf ) ;
for ( i = 1 ; i < NumInt - 1 ; i++ )
Y
{
Integral += 2 * Func( Intervalo * i ) ; } /* for */ Integral *= Intervalo/2; return Integral ; } /* Integrar */ A B X 0 1 2 3 4 5 6 7 8
m m m
TR h f f f f f f f I 02 1 2 3 2 1 2 Exemplo simples: integração, uso
/* exemplo de uso */double Quadrado( double X ) {
t X ** 2 return X ** 2 ; }
double Cubo( double X ) {
return X ** 3 ; }
printf( ″\n F = x ** 2 de x=1 a x=10: %lf″
Maio 2009 Alessandro Garcia © LES/DI/PUC-Rio 15 / 32 printf( \n F = x 2 de x=1 a x=10: %lf ,
Integrar( 1.0 , 10.0 , 20 , Quadrado )) ; printf( ″\n F = x ** 3 de x=1 a x=10: %lf″ ,
Integrar( 1.0 , 10.0 , 20 , Cubo )) ;
Função como um dado
• A assinatura pode estar associada a um de vários corpos
– na hora da chamadaé estabelecida a associação da chamada • estática(tempo de compilação), caso normal de linguagens procedurais
• dinâmica(tempo de execução), caso freqüente em linguagens orientadas a objetos Chama F( float ) Associação da chamada *F( float ) F( int ) Associação estática Assinatura Assinatura
Maio 2009 Alessandro Garcia © LES/DI/PUC-Rio 16 / 32 Corpo F( float ) Corpo F ( int ) Corpo F( float ) Associação dinâmica
Da aula passada... Para aula de hoje...
•
Objetivos
– discutir os conceitos de programação orientada a objetos (OO) do ponto de vista de programação modular
– o que são padrões de projeto?
– discutir como projetar programas C de forma reusável
• com padrões de projeto (ex. esquemas de algoritmos, estruturas de cabeças, etc...)
– discutir como projetar programas OO de forma reusável
• com padrões de projeto
• fazem sentido em programação modular em C?
Maio 2009 Alessandro Garcia © LES/DI/PUC-Rio 17 / 27 fazem sentido em programação modular em C?
Sumário
•
Introdução à padrões de projeto
•
Padrões de projeto em C
– Estrutura cabeça – Esquemas de algoritmo: • Pesquisa Binária – Iterador•
Padrões de projeto OO
– Singletong – Adapter – Observer – Etc...Iterador: exemplo de esquema de algoritmo
• Problema: como seqüencialmente acessar os elementos de umconjunto de dados (ordenado ou não), expondo o mínimo possível da sua representação interna?
• Solução de projeto: Um iterador(função geradora) é um esquema de algoritmo composto por:
– tipo tpEstado: o descritor (tipo) do estado
• possivelmente define uma constante: ESTADO_NIL
– um ou mais tipos tpValorX que determinam o tipo dos elementos acessados pela correspondente função:
tpValorX ObterValorX( tpEstado , ...)
E i di l d l d id
Maio 2009 Alessandro Garcia © LES/DI/PUC-Rio 19 / 27
• E.g. indice atual de um valor sendo percorrido
• valores acessíveis à partir do escritor do estado
– função tpEstado DefinirPrimeiro( ... )
– função tpEstado DefinirProximo( tpEstado , ... )
– função boolean Terminou( tpEstado , ... )
Iterador: exemplo pesquisa em tabela
•
Esquema do algoritmo para
pesquisa em qualquer tabela
tpEstado
Corrente ;
Corrente =
DefinirPrimeiro
( ValorProcurado ) ;
while ( !
Terminou
( Corrente ))
{
if (
Comparar
(
ObterValor
( Corrente ),
ValorProcurado ) == EH_IGUAL )
{
return Corrente ;
} /* if */
Maio 2009 Alessandro Garcia © LES/DI/PUC-Rio 20 / 27
} /
/
Corrente =
DefinirProximo
(Corrente, ValorProcurado);
} /* while */
Padrões de projeto
• Servem para resolver problemas/perguntas recorrentesem projeto (e programação) de software
– Exemplo: como implementar um mecanismo de observação?
• Estabelecem soluções elegantes para tais problemas
– definem papéis/participantes (módulos conceituais)a serem implementados
– soluções não são suportadas diretamentepor uma primitiva única da linguagem (p.e. Singleton)
– provêem exemplos em uma linguagem de programação(p.e. Java)
• Através de nomes/metáforas, um catálogo de padrões permite
Maio 2009 Alessandro Garcia © LES/DI/PUC-Rio 21 / 27 estabelecer um idioma entre programadores
– Comunicação eficiente: “Vamos usar o padrão Adapter para …”
• Estabelece as conseqüências positivas e negativasde usar aquele padrão: reuso, manutenibilidade, segurança, performance, etc...
Padrões de projeto
• Exemplos de padrões de projeto OO:
– Singleton Strategy
Padrões de problemas
Padrões de soluções
– Strategy
– Adapter
– Template Method
– Observer
– State
• Vantagem: reuso e manutenibilidade do código genérico dos padrões
– de um projeto para outro
– dentro de um projeto, poder have várias instâncias do mesmo padrão
• História: desde os anos 90, padrões OO em engenharia de software
• 1995, Gang of Four (Gamma, Helm, Johnson, Vlissides): “Design Patterns: Elements of Reusable Object-Oriented Software”
– criação (Singleton), estrutural (Adapter), comportamental (Observer)
Criação:
Padrão Singleton (Objeto Unitário)
1a instanciação
Classe Singleton Objeto único da
classe singleton
Maio 2009 Alessandro Garcia © LES/DI/PUC-Rio 23 / 27
Instanciações
subsequentes
Padrão Singleton (Objeto Unitário)
SecurityManager
private SecurityManager( )
public static SecurityManager getInstance( ) // other methods
private static SecurityManager uniqueInstance // other attributes
Uma classe singleton sempre tem uma variável estática privada para manter a instância única Um construtor privado
Maio 2009 Alessandro Garcia © LES/DI/PUC-Rio 24 / 27 // other methods…
Um método público estático para invocar o construtor privado se uniqueInstance é null; caso contrário, retorna uniqueInstance
Padrão Strategy (Estratégia)
•
Encapsula variantes de um algoritmo relacionados em classes
que são subclasses de uma classe comum
•
Permite a seleção de algoritmo variar por objeto e também no
decorrer do tempo
p
– estratégias podem variar de forma independente de clientes
– evita tornar complexa a classe contexto com diferentes algoritmos (e respectivas estruturas de dados) para o mesmo propósito
•
Forma Geral:
Java: pode ser uma classe abstrata ou interface
Maio 2009 Alessandro Garcia © LES/DI/PUC-Rio 25 / 27
Padrão Estratégia – Exemplo 1
qual padrão/conceito
poderia ser usado em combinação com o padrão Estratégia?
número de métodos abstratos pode variar de aplicação para aplicação
Padrão Estratégia – Exemplo 2
Maio 2009 Alessandro Garcia © LES/DI/PUC-Rio 27 / 27 número de métodos
abstratos pode variar de aplicação para aplicação
Padrão Estratégia – Exemplo 2
public class BubbleSort implements SortStrategy {
public void sort(double[] list) {
double temp;
for(int i = 0; i < list.length; i++) { for(int j = 0; j < list.length - i; j++) {
if(list[i] < list[j]) {
Maio 2009 Alessandro Garcia © LES/DI/PUC-Rio 28 / 27 temp = list[i]; list[i] = list[j]; list[j] = temp; } } } } }
Padrão Estratégia – Exemplo 2
public class QuickSort implements SortStrategy {
public void sort(double[] a) {
quicksort(a, 0, a.length - 1); }
private void quicksort(double[] a, int left, int right) {
Maio 2009 Alessandro Garcia © LES/DI/PUC-Rio 29 / 27
p q ( [] , , g ) {
if (right <= left) return; int i = partition(a, left, right); quicksort(a, left, i-1); quicksort(a, i+1, right); }
private int partition(double[] a, int left, int right) {…};
… }
Padrão Estratégia – Exemplo 2
SortingClient
public class SortArray {
private SortStrategy sorter = null;
public void sortDouble(double[] list) { sorter.sort(list);
}
public class SortingClient {
public static void main(String[] args) { double[] list = {1,2.4,7.9,3.2,1.2,0.2, …}; SortArray context = new SortArray(); context.setSorter(new BubbleSort()); Context
public SortInterface getSorter() { return sorter;
}
public void setSorter(SortStrategy sorter) { this.sorter = sorter;
}
context.sortDouble(list); for(int i =0; i< list.length; i++) {
System.out.println(list[i]); } context.setSorter(new QuickSort()); … context.setSorter(new InsertionSort()); }
Padrão Estratégia
•
Conseqüências
– Benefícios
• evolução modular das estratégias
• permite facilmente a troca dinâmica das estratégias para o mesmo contexto
– qual mecanismo de OO permite isso? é possível em C?
– desvantagens
• aumenta o número de objetos
– pode ter um efeito negativo sobre performance devido a criação de objetos para cada troca de estratégia
todos algo itmos de em sa a mesma inte face St ateg
Maio 2009 Alessandro Garcia © LES/DI/PUC-Rio 31 / 27
• todos algoritmos devem usar a mesma interface Strategy
– nem sempre é natural ou possível
Comportamental: Padrão Observer
Maio 2009 Alessandro Garcia © LES/DI/PUC-Rio 32 / 27
Sujeito Observado
Observadores
- Sujeito é independente dos observadores
- Observadores são atribuidos dinamicamente aos observados
- Sujeito informa observadores sobre suas mudanças de estado
Comportamental: Padrão Observer
variantes
: uso de interfaces ou classes abstratas
Maio 2009 Alessandro Garcia © LES/DI/PUC-Rio 33 / 27
Padrão Observer
•
O Padrão Observer
– paper “subject”: elemento do sistema sendo observado
• mantém referências para os “observadores”
• notifica os observadores que mudanças ocorreram
• notifica os observadores que mudanças ocorreram
Point Line FigureElement Figure 1 * Screen update <<interface>> Observer addObserver removeObserver notify <<interface>> Subject * *
Members exclusively dedicated to the pattern Methods including some code relative to the pattern
observers getX getY getColor addObserver removeObserver notify setX setY setColor update Display Sc ee observers getP1 getP2 getColor addObserver removeObserver notify setP1 setP2 setColor * *
Estrutural:
Padrão Adaptador
•
A função de um adaptador é tornar possível a conexão de
dois objetos: a tomada e o plugue de diferentes países
– converte a interface de uma classe (A) em outra interface (B) que clientes (C) conhecem
– Classes adaptadoras permitem duas classes (com interfaces
– Classes adaptadoras permitem duas classes (com interfaces originalmente incompatíveis) interagirem
classe (componente) existente (funcionalidade externa)
objeto cliente provided
interface
Maio 2009 Alessandro Garcia © LES/DI/PUC-Rio 35 / 27
Tomada Alemã
Adaptador
Plugue UK
A
B
C
required interface
Padrão Adapter (Adaptador)
•
Permite que uma aplicação utilize funcionalidades externas
•
Uma classe Adapter implementa uma interface conhecida
dos clientes e permite acesso a instâncias de uma classe
não conhecida dos clientes.
•
Exemplo:
SystemOutPrinter printToSystemOut(String s) … write () Writer <<inteface>>adaptado
adaptador
Maio 2009 Alessandro Garcia © LES/DI/PUC-Rio 36 / 27 PrinterAdapter adaptee write() Client writerObject.write()
adaptador
Aula 24
Programação Modular com
Padrões de Projeto
Alessandro Garcia Alessandro Garcia LES/DI/PUC-Rio