MAC 413/5715 - Tópicos de Programação
Orientada a
Objetos
Aula 5 - 24/8/2005
Padrões Arquiteturais (POSA I, II e III)
A origem da idéia dos padrões: Padrões
Alexandrinos:
Nome
Discussão técnica: quais as
questões/forças envolvidas
PORTANTO: uma solução comum para estas
questões/forças
C. Alexander et al. A Pattern Language -
Towns.Buildings.Construction . Oxford University Press, 1977.
Exemplo: Window Place
Contexto: todos nós adoraramos nos sentar
próximos a uma janela e apreciar a paisagem. Uma sala sem
janelas que podem ser apreciadas raramente nos faz sentir
confortáveis.
Problema: se uma sala contém uma janela perto da qual
não podemos sentar, uma pessoa nessa sala vai ser puxada por
duas forças antagônicas:
ela quer sentar e se sentir confortável
ela é atraída para perto da janela
Solução: obviamente, se não há um
lugar próximo à janela onde se pode sentar
confortavelmente, não há como resolver este conflito.
PORTANTO: em qualquer sala na qual as pessoas passam um certo tempo
durante o dia, faça com que pelo menos uma janela seja um lugar
para se sentar.
Diagrama.
Pattern-Oriented Software Architecture
POSA I: A System of Patterns
POSA II: Patterns for Networked and Concurrent Objects
POSA III: Patterns for
Resource Management
Ao escrever um padrão, veja se você tem bem claro 3
coisas que devem estar contidas na descrição do
padrão:
Contexto: uma situação que leva a um problema
Problema: um problema recorrente que acontece em determinada
situação
Solução: uma solução comprovada
para problema
Os padrões do POSA I se dividem em 3 grupos:
Architectural Patterns (alto nível)
Da lama à estrutura
Layers
Pipes and Filters
Blackboard
Sistemas Distribuídos
Broker
Sistemas Interativos
Model-View-Controller
Presentation-Abstraction-Control
Sistemas Adaptáveis
Microkernel
Reflection
Design Patterns (nível médio)
Decomposição Estrutural
Whole-Part
Organização de Trabalho
Master-Slave
Controle de Acesso
Proxy
Gerenciamento
Command Processor
View Handler
Comunicação
Forward-Receiver
Client-Dispatch-Server
Publisher-Subscriber
Idioms (baixo nível)
Counted Pointer
Cartões CRC (Class, Responsibility, Collaborator)
Exemplo, padrão Camadas:
Class
Camada J
Responsibility
Provê serviços usados pela camada
J+1
Delega subtarefas para a camada J-1
Collaborator
Camada J-1
Exemplo concreto de uso do padrão:
FTP em cima de TCP em cima de IP em
cima de Ethernet em cima de cabo de par trançado.
Padrão de Projeto: Publisher-Subscriber
É na verdade o Observer (293) do GoF.
O POSA o inclui para descrever variantes interessantes do
padrão
Problema:
em alguns sistemas, os dados mudam em um certo lugar e
vários objetos em outras partes do sistema dependem daqueles
dados; é necessário então, utilizar algum
mecanismo para informar os dependentes das mudanças.
poder-se-ia introduzir chamadas explícitas do objeto
cujo estado mudou para os seus dependentes, mas esta
solução não é flexível nem
reutilizável.
precisamos de um mecanismo de propagação de
mudanças que possa ser aplicado em vários contextos
A solução tem que equilibrar as seguintes forças:
um ou mais objetos tem que ser notificados sobre
mudanças em um objeto
o número de dependentes não é conhecido
a priori e pode até mudar dinamicamente
fazer com que os dependentes peguem o estado de tempos em
tempos (polling) é
muito caro
o objeto que provê o dado e aqueles que o consomem
não devem ser fortemente acoplados
Solução:
O objeto que contém o dado que interessa é
chamado de Publisher (subject no GoF)
Os objetos dependentes são chamados de Subscribers (observers no GoF)
O publisher mantém uma lista dos objetos registrados que
são aqueles interessados em receber notificações
sobre as mudanças.
O publisher oferece uma interface para
manifestação de interesse (subscribe interface)
Quando o estado do publisher muda, ele envia uma
notificação para todos os objetos que manifestaram
interesse.
Ao receber uma notificação, o subscriber decide
se solicita a informação ao publisher ou não.
Há vários graus de liberdade ao implementar o
padrão:
pode-se utilizar classes abstratas para implementar o
comportamento básico do padrão
o publisher pode decidir quais partes do seu estado interno
serão notificadas
o publisher pode decidir enfileirar as mudanças de
estado antes de enviar as notificações
um objeto pode se inscrever em vários publishers
um objeto pode ser simultaneamente publisher e subscriber
inscrição e notificação pode ser
filtrada de acordo com o tipo de evento gerado, ou tipo de dado que foi
alterado
o publisher pode enviar junto com a notificação
informações sobre o que mudou, ou não
Dois extremos:
modelo push (pouca
flexibilidade mas possivelmente melhor uso da banda)
modelo pull (mais
flexibilidade mas maior número de mensagens)
Variações
Gatekeeper
Versão distribuída do padrão
um publisher em um processo notifica subscribers remotos
o publisher pode ser dividido em dois processos
um processo gera os eventos
outro processo faz a demultiplexação definindo
quais subscribers o receberão e enviando as mensagens
Event channel
Proposto pela OMG no CORBA Event Service
desacopla ainda mais os produtores dos consumidores incluindo
um canal (channel) ligando os
dois
neste caso, os consumidores não precisam saber a origem
dos eventos, não interessa quem é o publisher, o que
interessa é o que foi publicado
um ou mais canais são introduzidos no meio de um ou mais
publishers e um ou mais subscribers
para os publishers, o event channel se parece com um subscriber
para os subscribers, o event channel se parece com um publisher
publishers, channels e subscribers podem residir em
máquinas distintas
channels podem oferecer serviços adicionais:
bufferização, filtragem, priorização
Producer-consumer
dois threads em um processo ou dois processos em uma
máquina que compartilham um buffer
um deles produz dados e coloca no buffer e o outro os retira do
buffer e os consome
não há comunicação direta entre
eles, mas há controle do acesso concorrente ao buffer
compartilhado
há uma relação de 1:1 que não
existe nas outras variantes do padrão
Padrão Arquitetural para Sistemas Adaptáveis: Microkernel
O uso de micronúcleos se aplica a sistemas que precisam
ser adaptados
para mudanças nos requisitos.
Premissa básica do bom programador OO: Design for
Change.
Exemplo:
Sistema operacional hipotético Hydra no qual podemos
executar
aplicações Windows, UNIX System V ou NeXTSTEP
simultaneamente em diferentes janelas.
Contexto:
Desenvolvimento de várias aplicações que
utilizam interfaces programáticas similares baseadas numa mesma
funcionalidade.
Problema:
Software básico é utilizado ao longo de muitos
anos, às vezes décadas. Ao longo da sua vida, acontecem
muitas mudanças no hardware, nos modelos de
programação, nos tipos de bibliotecas utilizadas, e nos
requisitos das aplicações.
O núcleo da funcionalidade do software básico
deve ser
encapsulado em uma componente que seja o menor possível e que
consuma
o mínimo possível de recursos computacionais para
não prejudicar as aplicações para as quais ele
oferece suporte.
Solução:
Encapsule os serviçoes fundamentais da sua plataforma em
uma
componente chamada "micronúcleo".
O micronúcleo oferece os seus serviços
básicos através de sua interface bem definida.
Funcionalidade que não é essencial e que
não pode ser implementada sem aumentar a complexidade do
micronúcleo deve ser implementada em "servidores internos" que
estendem a funcionalidade do micronúcleo.
Outras componentes chamdas de "servidores externos" utilizam a
interface
do micronúcleo para prover outros tipos de interfaces baseadas
na
funcionalidade exportada pelo micronúcleo.
Os clientes (aplicações) interagem com o sistema
através
dos servidores externos.
Estrutura:
Diagrama de classes
Usos conhecidos:
Sistemas operacionais baseados em micronúcleos:
Mach (CMU, 1986), hoje base do MacOS X
Amoeba (Tanenbaum, 92), OS orientado a objetos
Windows NT (Microsoft, 93), oferecia 3 servidores externos:
OS/2, POSIX e Win32.
Banco de Dados basedo em micronúcleo:
MKDE (Microkernel DatenBank Engine) de 1996. Diferentes tipos
de
bancos de dados com interfaces diferentes são implementados em
cima
de um microkernel básico.
Middleware de Comunicação:
UIC - Universally Interoperable Core (Román, 2000). O
micronúcleo
contém apenas
um arcabouço abstrato para construção
de
middleware para objetos distribuídos
um mecanismo para carga dinâmica de componentes para
integrar
o arcabouço
Isso é suficiente para carregar incrementalmente em
tempo de execução um middleware para
comunicação em
sistemas distribuídos, por exemplo, um subconjunto de CORBA.
Servidor de Aplicações:
JBoss
Plataforma para criação de
aplicações locais
Eclipse Rich Client Platform
Referência
F. Buschmann, R. Meunier, H. Rohnert, P.Sommerlad, M. Stal Pattern-Oriented
Software Architecture - A System of Patterns. John Wiley and Sons
Ltd, Chichester, UK, 1996