UNIVERSIDADE FEDERAL DE SANTA CATARINA de... · “A Engenharia de Software é uma disciplina da...

130
UNIVERSIDADE FEDERAL DE SANTA CATARINA DEPARTAMENTO DE INFORMÁTICA E ESTATÍSTICA CURSO DE CIÊNCIAS DA COMPUTAÇÃO USO DE PADRÕES DE ANÁLISE E PADRÕES DE PROJETO NO DESENVOLVIMENTO DE UMA APLICAÇÃO DE CONTROLE DE ATACADO Autor: Igor Tibes Ghisi Orientadora: Dr.ª Patrícia Vilain Banca Examinadora: Dr. Ricardo Pereira e Silva Dr. Ronaldo dos Santos Mello Palavras-chave: padrões de análise, padrões de projeto Florianópolis, 10 de março de 2004

Transcript of UNIVERSIDADE FEDERAL DE SANTA CATARINA de... · “A Engenharia de Software é uma disciplina da...

UNIVERSIDADE FEDERAL DE SANTA CATARINA

DEPARTAMENTO DE INFORMÁTICA E ESTATÍSTICA

CURSO DE CIÊNCIAS DA COMPUTAÇÃO

USO DE PADRÕES DE ANÁLISE E PADRÕES DE

PROJETO NO DESENVOLVIMENTO DE UMA

APLICAÇÃO DE CONTROLE DE ATACADO

Autor: Igor Tibes Ghisi

Orientadora: Dr.ª Patrícia Vilain

Banca Examinadora: Dr. Ricardo Pereira e Silva

Dr. Ronaldo dos Santos Mello

Palavras-chave: padrões de análise, padrões de projeto

Florianópolis, 10 de março de 2004

Agradecimentos

Agradeço primeiro e mais especialmente à minha orientadora, Prof. Patrícia

Vilain, pela paciência, preocupação e dedicação na orientação do trabalho.

Ao Prof. Ronaldo dos Santos Mello, pela correção e pelas orientações.

Ao Prof. Ricardo Pereira e Silva, pela avaliação criteriosa e imparcial.

Ao Prof. Orestes Estevam Alarcon e à Renata Santos, que cederam

equipamentos para implementação e apresentação do trabalho.

A minha família, Ivo, Arlete e Alice, pela compreensão e força que me deram.

Aos meus amigos, colegas de faculdade e colegas de trabalho pelo apoio e pelas

informações que me ajudaram a realizar o trabalho.

RESUMO

Este trabalho tem como objetivo desenvolver um estudo sobre o uso de padrões de

análise e padrões de projeto no processo de produção de software. Foram descritos

alguns padrões de análise e de projeto e fez-se um mapeamento dos padrões de análise

para padrões de projeto, quando pertinente. Para aplicar os padrões estudados e o

mapeamento definido desenvolveu-se uma aplicação de Controle de Atacado, utilizando

alguns padrões descritos. Também foi discutido o impacto destes na qualidade do

software desenvolvido.

Palavras-chave: padrões de análise, padrões de projeto.

ABSTRACT

The goal of this work is develop a study about the use of analysis patterns and design

patterns on the software development. Some analysis and design patterns were

described and a mapping of some analysis patterns to design patterns was proposed. A

software for Inventory Control was built applying some patterns and the mapping

defined. Also, the impact of patterns application in the quality of developed software

was discussed.

Key words: analisys patterns, design patterns.

SUMÁRIO

RESUMO

ABSTRACT

SUMÁRIO

ÍNDICE DE FIGURAS

1 INTRODUÇÃO ...................................................................................................... 10

1.1 CARACTERIZAÇÃO DO TEMA E MOTIVAÇÃO....................................................... 10

1.2 OBJETIVOS ............................................................................................................ 11

1.2.1 OBJETIVO GERAL ................................................................................................. 11

1.2.2 OBJETIVOS ESPECÍFICOS ...................................................................................... 11

2 RATIONAL UNIFIED PROCCESS .................................................................... 12

2.1 ESTRUTURA ........................................................................................................... 13

2.2 WORKFLOW MODELAGEM DE NEGÓCIOS............................................................. 16

2.3 WORKFLOW DE REQUISITOS.................................................................................. 16

2.4 WORKFLOW DE ANÁLISE E PROJETO .................................................................... 17

3 PADRÕES DE ANÁLISE...................................................................................... 19

3.1 RESPONSABILIDADE .............................................................................................. 19

3.1.1 ENTIDADE............................................................................................................ 19

3.1.2 HIERARQUIA DE ORGANIZAÇÕES......................................................................... 21

3.1.3 ESTRUTURA DE ORGANIZAÇÕES .......................................................................... 22

3.1.4 RESPONSABILIDADE ............................................................................................ 24

3.1.5 NÍVEL DE INFORMAÇÃO DE RESPONSABILIDADE ................................................. 25

3.2 ESTOQUE E CONTABILIDADE................................................................................ 27

3.2.1 PADRÃO CONTA .................................................................................................. 27

3.2.2 TRANSAÇÕES....................................................................................................... 28

3.2.3 TRANSAÇÕES MÚLTIPLAS.................................................................................... 29

3.2.4 CONTA RESUMIDA............................................................................................... 30

3.2.5 CONTA GATILHO ................................................................................................. 31

3.2.6 REGRA DE LANÇAMENTO .................................................................................... 32

3.2.7 REGRAS DE LANÇAMENTOS PARA VÁRIAS CONTAS.............................................. 33

3.3 COMÉRCIO ............................................................................................................ 35

3.3.1 CONTRATO .......................................................................................................... 36

3.3.2 PORTFÓLIO .......................................................................................................... 38

4 PADRÕES DE PROJETO..................................................................................... 41

4.1 SINGLETON............................................................................................................. 41

4.2 FACTORY METHOD................................................................................................. 43

4.2.1 ESTRUTURA ......................................................................................................... 45

4.2.2 IMPLEMENTAÇÃO ................................................................................................ 46

4.3 PROXY .................................................................................................................... 46

4.3.1 IMPLEMENTAÇÃO ................................................................................................ 47

4.3.2 ESTRUTURA ......................................................................................................... 48

4.4 FACADE.................................................................................................................. 49

4.4.1 IMPLEMENTAÇÃO ................................................................................................ 51

4.4.2 ESTRUTURA ......................................................................................................... 52

4.5 STATE ..................................................................................................................... 53

4.5.1 ESTRUTURA ......................................................................................................... 54

4.5.2 IMPLEMENTAÇÃO ................................................................................................ 54

4.6 COMPOSITE ............................................................................................................ 56

4.6.1 ESTRUTURA ......................................................................................................... 56

4.6.2 IMPLEMENTAÇÃO ................................................................................................ 57

4.7 STRATEGY .............................................................................................................. 58

4.7.1 ESTRUTURA ......................................................................................................... 58

4.7.2 IMPLEMENTAÇÃO ................................................................................................ 58

5 MAPEAMENTO DE PADRÕES DE ANÁLISE PARA PADRÕES DE

PROJETO ..................................................................................................................... 60

5.1 PADRÃO DE ANÁLISE TRANSAÇÕES E PADRÃO DE PROJETO PROXY................... 60

5.2 PADRÃO DE ANÁLISE CONTA RESUMIDA E PADRÃO DE PROJETO COMPOSITE .. 61

5.3 PADRÃO DE ANÁLISE PORTFÓLIO E PADRÃO DE PROJETO STRATEGY ............... 64

5.3.1 USO DO SINGLETON.............................................................................................. 66

5.4 PADRÃO DE ANÁLISE REGRA DE LANÇAMENTO E PADRÃO STRATEGY............... 67

6 DESENVOLVIMENTO......................................................................................... 69

6.1 LEVANTAMENTO DE REQUISITOS......................................................................... 69

6.1.1 DESCRIÇÃO DO DOMÍNIO DA APLICAÇÃO............................................................ 69

6.1.2 CASOS DE USO..................................................................................................... 70

6.2 ANÁLISE ................................................................................................................ 80

6.2.1 MODELO CONCEITUAL ........................................................................................ 80

6.3 PROJETO................................................................................................................ 88

6.3.1 LINGUAGEM E BANCO DE DADOS ........................................................................ 88

6.3.2 DIAGRAMAS DE SEQUÊNCIA ................................................................................ 89

6.3.2.1 Consignar......................................................................................................... 90

6.3.2.2 Vender ............................................................................................................. 91

6.3.3 DIAGRAMA DE CLASSES ...................................................................................... 92

6.3.3.1 Contratos.......................................................................................................... 92

6.3.3.2 Conta Caixa ..................................................................................................... 94

6.3.3.3 Camada de Persistência ................................................................................... 96

6.4 IMPLEMENTAÇÃO.................................................................................................. 98

6.4.1 MÉTODO VENDER................................................................................................ 98

6.4.2 MÉTODO OBTERVENDAS ..................................................................................... 99

6.4.3 CAMADA DE PERSISTÊNCIA ............................................................................... 100

6.4.4 PROTÓTIPO ........................................................................................................ 101

6.4.4.1 Funcionamento do Protótipo ......................................................................... 102

7 CONCLUSÃO....................................................................................................... 104

7.1 FATORES DE QUALIDADE ALCANÇADOS ............................................................ 104

7.1.1 ESTENDIBILIDADE ............................................................................................. 104

7.1.2 DESEMPENHO .................................................................................................... 105

7.1.3 REUSABILIDADE ................................................................................................ 105

7.1.4 PORTABILIDADE ................................................................................................ 105

7.2 CONSIDERAÇÕES FINAIS..................................................................................... 106

BIBLIOGRAFIA CONSULTADA ........................................................................... 107

ANEXOS ..................................................................................................................... 109

ANEXO I: ARTIGO ..................................................................................................... 110

ANEXO II: DIAGRAMA DE CLASSES (CAMADA DE APLICAÇÃO).............................. 112

ANEXO III: CÓDIGO DA APLICAÇÃO ........................................................................ 114

ÍNDICE DE FIGURAS

Figura 3.1 – Padrão Entidade ......................................................................................... 20

Figura 3.2 – Modelo de hierarquia simples .................................................................... 21

Figura 3.3 – Modelo de hierarquia com restrições ......................................................... 22

Figura 3.4 – Estrutura de Organização ........................................................................... 23

Figura 3.5 – Hierarquia utilizando padrão Entidade....................................................... 24

Figura 3.6 – Divisão em camadas................................................................................... 26

Figura 3.7 – Conta e Lançamento................................................................................... 27

Figura 3.8 - Transação.................................................................................................... 29

Figura 3.9 – Transação Múltipla .................................................................................... 30

Figura 3.10 – Conta Resumida ....................................................................................... 30

Figura 3.11 – Regra de Lançamento............................................................................... 32

Figura 3.12 – Metodo de Cálculo para saida .................................................................. 33

Figura 3.13 – Conta e Tipo de Conta.............................................................................. 34

Figura 3.14 – Localizador de Conta ............................................................................... 35

Figura 3.15 – Contrato com especificação ..................................................................... 36

Figura 3.16 – Contrato com associações ........................................................................ 37

Figura 3.17 - Contrato .................................................................................................... 37

Figura 3.18 - Portfólio .................................................................................................... 38

Figura 3.19 – Seleção de Contratos por método booleano............................................. 39

Figura 3.20 – Seleção de Contratos por comparação com Seletor ................................. 40

Figura 4.1 – Estrutura do Padrão Singleton.................................................................... 42

Figura 4.2 – Estrutura do Factory Method ..................................................................... 45

Figura 4.3 – Exemplo do Proxy...................................................................................... 47

Figura 4.4 – Etrutura do Proxy ....................................................................................... 49

Figura 4.5 – Sem o uso do Facade ................................................................................. 50

Figura 4.6 – Com o uso do Facade ................................................................................. 51

Figura 4.7 – Estrutura do Facade ................................................................................... 52

Figura 4.8 – Padrão State................................................................................................ 53

Figura 4.9 – Estrutura do State ....................................................................................... 54

Figura 4.10 – Estrutura do Composite ............................................................................ 56

Figura 4.11 – Estrutura do padrão Strategy.................................................................... 58

Figura 4.12 – Estrutura do Strategy................................................................................ 59

Figura 5.1 – Estrutura do Proxy ..................................................................................... 61

Figura 5.2 – Padrão de Análise Conta Resumida ........................................................... 62

Figura 5.3 - Padrão de Projeto Composite...................................................................... 62

Figura 5.4 – Diagrama de classe do mapeamento .......................................................... 63

Figura 5.5 – Seleção de contrato por método ................................................................. 64

Figura 5.6 – Estrutura da implementação....................................................................... 65

Figura 5.7 – Portfólio mapeado para Singleton e Strategy ............................................. 66

Figura 5.8 – Padrão de análise Regra de Lançamento.................................................... 67

Figura 5.9 – Mapeamento do Padrão Regra de Lançamento para o Strategy ................ 67

Figura 6.1 – Modelo baseado no padrão Entidade ......................................................... 81

Figura 6.2 – Modelo sem conceito de Contrato.............................................................. 82

Figura 6.3 – Conceito de Contrato ................................................................................. 83

Figura 6.4 – Modelo com conceito de Contrato ............................................................. 84

Figura 6.5 – Conta Caixa, Receita e Despesa................................................................. 85

Figura 6.6 – Lançamentos nos Caixas ............................................................................ 86

Figura 6.7 – Modelo conceitual da aplicacao................................................................. 87

Figura 6.8 – Diagrama de Sequência Consignar ............................................................ 90

Figura 6.9 – Diagrama de Sequência Vender ................................................................. 91

Figura 6.10 – Contrato com Proxy ................................................................................. 93

Figura 6.11 – Heranças de contrato com Proxy.............................................................. 94

Figura 6.12 – Conta Resumida projetada para Caixas.................................................... 95

Figura 6.13 – Camada de Persistencia............................................................................ 97

Figura 6.14 - Protótipo da Aplicação............................................................................ 102

Figura 6.15 – Consultando o estoque ........................................................................... 103

Figura 6.16 – Realizando a venda ................................................................................ 103

Figura 6.17 – Consultando a venda realizada............................................................... 103

1 INTRODUÇÃO

1.1 Caracterização do Tema e Motivação

A capacidade da indústria de software dos dias atuais de desenvolver sistemas de

grande complexidade se deve à implementação de um tratamento sistemático e

controlado à etapa de desenvolvimento da solução computacional, o qual denomina-se

engenharia de software.

“A Engenharia de Software é uma disciplina da engenharia que se ocupa de

todos os aspectos da produção de software, desde os estágios iniciais de especificação

do sistema até a manutenção desse sistema” (SOMMERVILLE, 2003).

A engenharia de software surgiu nos anos 70 e hoje se tornou imprescindível

para qualquer softwarehouse que deseja, além de desenvolver aplicações maiores e mais

complexas, também garantir produtos de qualidade.

Dentre as ferramentas de engenharia de software que tornam possível a

complexidade dos sistemas atuais, estão os padrões. Os padrões são soluções utilizadas

no processo de desenvolvimento de uma aplicação que podem ser utilizadas novamente

em outro processo, mesmo que o domínio do problema seja diferente.

Dessa maneira, não é necessário dispender esforço na resolução de um problema

que já foi solucionado no passado.

“Cada padrão descreve um problema que ocorre mais de uma vez em um

certo contexto, e descreve o núcleo da solução para este problema de uma

forma que você pode usar essa solução um milhão de vezes, sem ter que

elabora-la novamente” (ALEXANDER, 1977 apud GAMMA, 1994)

Padrões são usados em vários campos de trabalho como construção civil e

gerenciamento empresarial. Foi adotado no desenvolvimento de software a partir dos

anos 90. Nos últimos anos os padrões têm sido bastante discutidos.

11

“Padrões não são inventados, mas sim descobertos” (FOWLER, 1997). Isso

porque a maioria dos padrões nasce de um modelo feito para um domínio particular, e o

desenvolvedor nota que o modelo pode ser usado em outros domínios. Assim o modelo

se torna um padrão.

Neste trabalho realizou-se o estudo de padrões para duas fases do

desenvolvimento de software. Padrões para análise e padrões para projeto. Analisou-se,

também, como ocorre a utilização destes padrões no desenvolvimento da aplicação. E

quais os benefícios desta utilização.

1.2 Objetivos

1.2.1 Objetivo geral

Ao fim do trabalho deve-se ter uma descrição de vários padrões de análise e

padrões de projeto e, com o estudo de cada um, ver quais se adequam ao domínio da

aplicação e que facilidades estes trazem para desenvolvimento de uma aplicação de

controle de atacado.

1.2.2 Objetivos específicos

• Fazer um estudo de alguns padrões de análise.

• Fazer um estudo de alguns padrões de projetos.

• Fazer um mapeamento dos padrões de análise para os padrões de projeto.

• Desenvolver um modelo (análise e projeto) para o domínio de controle de

atacado, utilizando, sempre que pertinente, os padrões de análise e padrões de

projeto estudados.

• Implementar um protótipo da aplicação.

2 RATIONAL UNIFIED PROCCESS

Dentro de um processo de desenvolvimento, o Rational Unified Proccess (RUP)

(KRUCHTEN, 2000) disponibiliza uma abordagem disciplinada para a atribuição de

tarefas e responsabilidades e assegura a produção de um software de alto padrão.

De acordo com Booch (BOOCH apud KRUCHTEN, 2000) um processo de

desenvolvimento de software deve possuir quatro funções:

1. Ordenar as atividades da equipe de desenvolvimento.

2. Especificar quais artefatos de software deverão ser desenvolvidos e quando

deverão ser desenvolvidos.

3. Definir as tarefas que serão individuais e tarefas executadas em conjunto

pela equipe.

4. Sugerir um critério de monitoração e avaliação dos produtos e atividades do

projeto.

“O processo de desenvolvimento de software sistematiza o desenvolvimento de

aplicações complexas e possibilita produzir um software de qualidade de uma maneira

previsível. Com isso, os custos de produção são reduzidos e a produtividade é elevada”

(KRUCHTEN, 2000)

Por ser um moderno processo de engenharia de software, provendo ferramentas

eficientes para assegurar a produção de sistemas de qualidade, o RUP se tornou um

padrão para a industria de desenvolvimento de software no mundo. Ele é considerado

como “um framework de processo que pode ser adaptado e estendido para satisfazer as

necessidades de uma organização” (KRUCHTEN, 2000).

“O objetivo do RUP é produzir software de qualidade, que promova uma

solução adequada as necessidades do usuário final.” (KRUCHTEN, 2000) Por isso, é

feita a adoção de casos de uso como elemento fundamental na construção do software,

servindo como base para todo o processo de desenvolvimento.

13

2.1 Estrutura

“Um processo descreve quem está fazendo o que, como e quando. O RUP é

representado usando-se quatro elementos primários de modelagem” (KRUCHTEN,

2000)

• Papéis: quem;

• Atividades: como;

• Artefatos: o que;

• Workflows: quando;

Papéis: Um papel define o comportamento e as responsabilidades de um

indivíduo ou um grupo de trabalho. Os comportamentos são expressos na forma de

atividades. Cada papel está associado a um conjunto de atividades que serão executadas.

“A responsabilidade de um papel está usualmente expressa em relação a certos artefatos

que os papéis criam, modificam ou controlam” (KRUCHTEN, 2000).

Um participante do projeto pode apresentar vários papéis durante o

desenvolvimento do software, e vários participantes podem apresentar o mesmo papel.

Kruchten faz uma analogia de papéis com “um chapéu que o indivíduo usa durante o

projeto. Uma pessoa pode usar vários chapéus” (KRUCHTEN, 2000) e um chapéu pode

ser usado por várias pessoas.

Exemplos de papéis:

• Analista: coordena a análise do domínio, compreensão dos requisitos e a

descrição dos casos de uso.

• Projetista: define as responsabilidades, operações, atributos e associações

de uma ou mais classes e determina sua ambientação no sistema.

Atividades: como visto anteriormente, as atividades descreverão o

comportamento dos papéis. Uma atividade é uma operação que um indivíduo num papel

deve executar, “e que produz um resultado significativo no contexto do projeto”

14

(KRUCHTEN, 2000) Normalmente, a atividade tem como objetivo a criação ou

modificação de um artefato.

A granularidade de uma atividade pode ir de algumas horas até dias. A atividade

deve ser usada como elemento de avanço do projeto. Ela pode se repetir muitas vezes

em cima do mesmo artefato “especialmente de uma iteração para outra, em que o

sistema está sendo refinado e expandido” (KRUCHTEN, 2000). A repetição de uma

atividade deve ser feita pelo mesmo papel.

Exemplo de atividades:

• Procurar Casos de Uso e Atores: executada pelo papel Analista.

• Executar um teste de performance: executada pelo papel Testador de

Performance.

Artefatos: “Um artefato é um pedaço de informação que é produzido, modificado

ou usado por um processo” (KRUCHTEN, 2000) Os artefatos vão sendo construídos e

utilizados ao longo do projeto. Normalmente, servem de entrada para uma atividade que

produz um outro artefato ou modifica este mesmo artefato.

Entre as formas que um artefato pode ter estão: um modelo conceitual do domínio;

um documento com a descrição do domínio do problema, um código fonte.

Um artefato também pode ser a composição de vários artefatos. Por exemplo, o

diagrama de classes de projeto é composto por classes.

A melhor maneira de criar e apresentar artefatos é utilizar-se das ferramentas

apropriadas para a criação dos mesmos. Nem todo artefato é um documento em papel

com texto ou representações. Geralmente eles são o resultado da ferramenta no qual

foram elaborados.

Exemplo de artefatos:

• Um modelo conceitual do Together.

• Um modelo de projeto do Rational Rose.

15

Os artefatos do RUP são classificados em cinco conjuntos de informação:

• Gerencial: artefatos relacionados ao gerenciamento do projeto.

• Requisitos: artefatos relacionados à definição do software a ser

desenvolvido como modelo de casos de uso e descrição de domínio.

• Projeto: artefatos relacionados à descrição do sistema como diagrama de

classes.

• Implementação: código fonte e executáveis.

• Implantação: material de instalação e documentação para o usuário.

Workflow: “é preciso uma forma para descrever uma seqüência de atividades que

produz resultados efetivos e mostre iteração entre os papéis. Um workflow é uma

seqüência de atividades que produz um resultado de considerável valor”. (KRUCHTEN,

2000)

O RUP é composto de nove workflows: seis workflows de engenharia e três

workflows de suporte. Eles representam uma divisão das atividades e papéis em áreas

lógicas. Os seis workflows de engenharia são:

• Modelagem de Negócios

• Requisitos

• Análise e Projeto

• Implementação

• Teste

• Implantação

Os três workflows de suporte:

• Gerenciamento de Projeto

• Gerenciamento de Configuração e Alterações

• Ambiente

16

A seguir serão abordados os workflows utilizados no desenvolvimento da

aplicação de controle de atacado até o presente momento.

2.2 Workflow Modelagem de Negócios

No workflow de modelagem de negócio a equipe irá fazer um estudo do

funcionamento da organização para a qual será desenvolvida uma aplicação. Como

resultado o workflow deve prover informações sobre toda a dinâmica do trabalho para o

qual será construída uma solução de software, identificar todos os processos, seus

problemas e indicar possíveis aperfeiçoamentos.

Principais artefatos desenvolvidos são: Descrição do Domínio, Descrição dos

Casos de Uso do Domínio.

2.3 Workflow de Requisitos

Os principais objetivos do workflow de requisitos são:

• Estabelecer, em acordo com cliente, o que o sistema que será desenvolvido

irá fazer

• Prover mais informações sobre os requisitos do sistema para os

desenvolvedores.

• Definir os limites do sistema (definir que parte do processo de trabalho irá

ser automatizada pela aplicação)

• Estabelecer prazos e custos.

• Definir a interface com o usuário do sistema.

Um requisito é “uma condição ou capacidade que um sistema deve obedecer”

(KRUCHTEN, 2000). Pode-se dividir os requisitos em funcionais e não-funcionais.

Os requisitos funcionais são ações que o sistema deve ser capaz de realizar.

Normalmente, esta ação é fruto de uma ordem externa ao sistema que deve gerar algum

17

resultado. Exemplo de requisitos funcionais: o sistema de supermercado deve registrar a

venda do produto e dar baixa do mesmo no estoque.

Os requisitos não-funcionais não são ações, mas sim características de

funcionamento do sistema. Exemplos de requisitos não-funcionais: o banco de dados

deve suportar mais de 1 milhão de registros; o sistema deve ter capacidade para

trabalhar com leitor de código de barras.

O primeiro passo para coletar os requisitos é elaborar um documento onde se

descreve o que o cliente espera do sistema,. que funções ele espera que o sistema realize

e que resultados devem ser apresentados. Este documento, chamado de documento de

visão, também deve conter as funções de alto nível do sistema. Serão as funções que

farão com que os requisitos do cliente sejam atendidos.

A partir deste documento será elaborado um modelo de caso de uso. “Um caso de

uso é um documento narrativo que descreve a seqüência de eventos de um ator (um

agente externo) que usa um sistema para completar um processo” (JACOBSON, 1992

apud LARMAN, 1997) O modelo de caso de uso é usado como coleta dos requisitos.

No workflow de requisitos também é feita a coleta de informações para projetar a

interface com o usuário do sistema. O modelo de caso de uso servirá como base de

informação para se desenvolver um protótipo de interface com o usuário. Com o

protótipo pronto o cliente e a própria equipe de desenvolvimento podem ter uma noção

da aplicação e assim elaborar os requisitos finais do sistema.

Principais artefatos desenvolvidos neste workflow são: documento de visão,

modelo de caso de uso e protótipo de interface com o usuário.

2.4 Workflow de Análise e Projeto

O objetivo deste workflow é transformar os requisitos em especificações que

descreverão como será feita a implementação do sistema. Para isso deve-se fazer um

estudo dos requisitos e transformá-los num modelo de sistema. Este modelo será então

ajustado de acordo com o ambiente de programação escolhido.

A primeira atividade do workflow consiste na construção de um modelo de análise

a partir do modelo de caso de uso. Através do modelo de casos de uso identificam-se

18

classes significativas para a construção de um modelo conceitual e neste modelo define-

se como estas classes interagem entre si.

Na segunda etapa, usa-se o modelo conceitual de análise para elaborar o projeto

do software. Os elementos do projeto serão baseados nos elementos do modelo

conceitual da análise e adicionam-se os artefatos de software. Descreve-se a

organização do sistema e sua arquitetura de execução.

Na terceira etapa, faz-se o projeto de artefatos de software como banco de dados,

protocolo de comunicação, ou outro artefato necessário ao atendimento dos requisitos

do sistema.

Principais artefatos desenvolvidos neste workflow são: modelo conceitual da

análise, diagrama de classes do projeto.

Os papéis do workflow descritos por Kruchten (2000) são:

Arquiteto: o arquiteto é o coordenador geral do workflow. Ele define a estrutura

geral dos modelos gerados e a interface entre os subsistemas modelados.

Projetista: elabora o modelo de projeto, constituido de operações, atributos,

responsabilidades e relacionamento de uma ou mais classes que definirão a

implementação do sistema. Normalmente um projetista fica responsável pela

modelagem de um ou mais subsistemas definidos pelo arquiteto.

Projetista de Banco de Dados: elabora o modelo de banco de dados, caso seja

necessário.

3 PADRÕES DE ANÁLISE

“Padrões de Análise são grupos de conceitos que representam uma construção

comum em modelagem de negócios. Podem ser relevantes em um domínio, ou abranger

muitos domínios” (FOWLER 1997, p. 8).

Os padrões de análise podem ser definidos como um conjunto de classes e

associações que representam de forma sistemática um contexto de uma aplicação. Esta

representação de contexto muitas vezes é válida para mais de uma aplicação, e isso faz

dos padrões de análise uma valiosa ferramenta de reuso. Fez-se um estudo de vários padrões de análise descritos por Fowler (1997) no

livro Analysis Patterns. Para descrever os modelos, Fowler usou a notação de Odell

(ODELL, 1995 apud FOWLER, 1997). Na transcrição dos modelos de Fowler para este

trabalho foi usada a notação UML.

3.1 Responsabilidade

Nesta seção estão descritos padrões que lidam com o conceito de

responsabilidade. Responsabilidade é um conceito abstrato que pode representar vários

tópicos como hierarquia de organização, vínculo empregatício, etc.

3.1.1 Entidade

Este é, freqüentemente, um dos primeiros padrões com que um analista iniciante

se depara. O padrão Entidade é utilizado para definir pessoas e organizações dentro do

modelo.

Como organizações e pessoas tem vários atributos comuns, como nome, endereço

e formas de contato (telefone, e-mail), pode-se generalizar pessoa e organização numa

classe chamada Entidade (figura 3.1).

20

Figura 3.1 – Padrão Entidade

Mas não são só os atributos que tornam Pessoa e Organização especificações da

mesma classe. Várias ações como pagamentos, envio de correspondência (e-mail ou

carta), pagamento de impostos e muitas outras são comuns às duas classes.

Fowler (1997) faz uma analogia de Entidade com uma agenda telefônica pessoal.

A maioria dos registros de uma agenda são de pessoas, mas alguns podem ser de

empresas, e nenhuma diferenciação é vista entre os registros de pessoas e empresas.

Logo abaixo do telefone de Paulo, por exemplo, pode estar o telefone da Panificadora

Pão Quente.

Segundo Fowler (1997), este padrão representa um caso típico de conceito não

nomeado:

“conceito não nomeado – todo mundo conhece e usa, mas ninguém tem

um nome para ele. Eu já o vi em incontáveis modelos de dados com vários

nomes: person/organization, player, legal entity e muitos outros”.

(FOWLER, 1997)

21

No Brasil encontra-se este padrão com nome de Pessoa/Organização ou mesmo

Pessoa, que generaliza Pessoa Física e Pessoa Jurídica.

3.1.2 Hierarquia de Organizações

Considere uma multinacional qualquer: Cervejaria Kicerva Ltda por exemplo. Ela

tem várias unidades operacionais espalhadas pelo mundo, as quais são divididas em

regiões, que por sua vez são divididas em sub-regiões, e estas divididas em escritórios

de venda. Pode-se representar esta situação com o seguinte modelo (figura 3.2):

Figura 3.2 – Modelo de hierarquia simples

Apesar de ser satisfatória a representação acima é pouco flexível. Se, por exemplo,

a Kicerva deseje fechar os escritórios sub-regionais (as regiões gerenciariam

diretamente os escritórios de venda), seriam necessárias alterações no modelo.

O modelo de hierarquia com associação recursiva (figura 3.3) possibilita essa

flexibilidade. Para definir as hierarquias no modelo, adiciona-se restrições aos subtipos

de organização para que eles saibam quem deve ser sua subordinada.

22

Figura 3.3 – Modelo de hierarquia com restrições

Caso haja uma mudança na hierarquia das organizações da empresa, simplesmente

altera-se a restrição de um subtipo. Neste ponto ganha-se flexibilidade, já que

geralmente é mais fácil mudar uma restrição do que alterar a estrutura de um modelo.

3.1.3 Estrutura de Organizações

Apesar de ser bastante flexível, algumas situações não podem ser representadas no

modelo de hierarquia com restrições (figura 3.3). Suponha que os escritórios de venda

da Kicerva sejam subordinados a uma sub-região, a qual devem reportar sobre suas

vendas, e subordinado também a uma unidade operacional de produção, a qual devem

reportar sobre a qualidade do produto Kicerva (o escritório é subordinado a duas

organizações).

Para representar este caso transforma-se a associação de hierarquia (associação

gerencia) em um conceito, e diferenciam-se os vários tipos de hierarquias através de

outro conceito, o conceito Tipo de Estrutura, como mostra a Figura 3.4.

23

Figura 3.4 – Estrutura de Organização

Exemplo 1: O escritório de vendas da Kicerva em Florianópolis está subordinado

à sub-região de vendas do Sul e a unidade operacional de qualidade de produto. Esta

representação seria feita com dois Tipos de Estrutura: vendas e qualidade de produto. O

Tipo de Estrutura venda definiria uma Estrutura de Organização com Sub-Região como

gerente e Escritório de Venda como subordinada. O Tipo de Estrutura qualidade de

produto definiria uma Estrutura de Organização com Unidade Operacional como

gerente e Escritório de Venda como subordinada.

Para apenas duas hierarquias, como no exemplo acima, talvez o modelo seja

subutilizado. Mas em casos onde há vários tipos de hierarquia, este modelo fornece a

flexibilidade necessária para lidar com tal complexidade.

As restrições, que antes eram definidas nos subtipos de Organização, agora podem

ser definidas no Tipo de Estrutura. Isso facilita a adição de novos Tipos de Estrutura,

mas por outro lado, dificulta a adição de novos subtipos de Organizações, já que cada

adição de um novo subtipo provoca uma alteração nas restrições de todos os Tipos de

Estruras que definem a hierarquia do subtipo adicionado.

24

Então a escolha de onde definir as restrições depende de uma análise do modelo

para verificar que área deste sofrerá mais adição de novos elementos. “Projete um

modelo para que as modificações mais frequentes do modelo cause o menor número de

alterações dos conceitos” (FOWLER 1997).

3.1.4 Responsabilidade

Pode-se estender o padrão anterior para ser usado não apenas com organizações,

mas com qualquer tipo de entidade que possua algum tipo de relacionamento de

responsabilidade.

O padrão Responsabilidade usa o mesmo modelo de Estrutura de Organizações,

apenas dando novos nomes aos conceitos e usando o padrão Entidade no lugar das

organizações. (figura 3.5)

Figura 3.5 – Hierarquia utilizando padrão Entidade

25

Exemplo 1: João da Silva trabalha na Cervejaria Kicerva. Isto pode ser modelado

como uma Responsabilidade na qual o responsável é a Kicerva e o dependente é João

Boanerges. O Tipo de Responsabilidade é emprego.

Exemplo 2: João da Silva é o gerente da equipe de vendas de Florianópolis. Isto

pode ser modelado como uma Responsabilidade em que o Responsável e João, o

dependente é a equipe de vendas de Florianópolis e o Tipo de Responsabilidade é

gerência.

3.1.5 Nível de Informação de Responsabilidade

O número de tipos de responsabilidade que se consegue representar é muito maior

que o número de tipos de estrutura no modelo de Estrutura de Organizações. Por isso as

restrições e regras entre as relações de dependência ficam bem mais complexas no

modelo Responsabilidade.

Essa complexidade pode ser gerenciada dividindo-o em duas camadas: uma de

nível operacional e uma de nível de informação. O nível operacional abriga conceitos

como Responsabilidade, Entidade e seus relacionamentos. O nível de informação abriga

conceitos como Tipo de Responsabilidade, Tipo de Entidade (figura 3.6).

O nível operacional registra atividades do dia-a-dia do domínio. O nível de

informação regulamenta essas atividades. No modelo da figura 3.6, uma instância de

Responsabilidade sofre as restrições definidas entre as relações de Tipo de

Responsabilidade e Tipo de Entidade.

26

Figura 3.6 – Divisão em camadas

Neste modelo, a associação “especifica” substitui as especializações de entidade.

Assim, Entidade pode ter seu comportamento definido pelo Tipo de Entidade ao qual

ele está associado.

A reflexão entre o nível de informação e o nível operacional é bastante parecida,

mas não igual. No nível operacional as associações dependente e responsável são de 1

para muitos, já no nível de informação elas passam a ser de muitos para muitos, pois o

nível operacional registra somente a Entidade em uso na operação, enquanto o nível de

informação registra todas as associações possíveis entre Entidades e Responsabilidades.

A divisão dos modelos em níveis de informação e operacional é comum, mas nem

sempre são explicitadas. Porém, isso ajuda a identificar melhor os comportamentos dos

conceitos no modelo.

27

3.2 Estoque e Contabilidade

Uma grande quantidade de sistemas computacionais comerciais é desenvolvida

para gerenciar a movimentação de dinheiro de uma empresa, basicamente registrando

como o dinheiro é ganho e depois gasto. A idéia básica por trás do gerenciamento de

contabilidade e estoque é que existem vários recipientes contendo dinheiro ou produtos

e é preciso registrar a movimentação do dinheiro e dos produtos através desses

recipientes.

Desta idéia básica nasceram os padrões Estoque e Contabilidade que serão

descritos neste trabalho. Eles apresentam uma coleção de conceitos que pode-se usar

como base para sistemas de contabilidade, controle de estoque e gerenciamento de

recursos.

3.2.1 Padrão Conta

O padrão Conta fornece conceitos básicos para o gerenciamento de

movimentação de um produto qualquer em um estoque genérico, como por exemplo,

litros de combustível em um posto de gasolina ou quantidade de dinheiro em um caixa

eletrônico.

Para isso é preciso detalhar as operações que modificam a quantidade dos

mesmos neste estoque.

No padrão Conta isso é feito registrando-se um Lançamento em uma respectiva

Conta a cada modificação no estoque destes produtos (Figura 3.7).

Figura 3.7 – Conta e Lançamento

28

Em Lançamento tem-se a data_lançamento que é a data real em que a operação

foi feita e a data_registro que é a data em que a operação foi registrada no sistema.

Em Conta tem-se o atributo saldo que é a soma da quantidade de todos os seus

Lançamentos.

Um Lançamento será definido como depósito ou retirada de acordo com o sinal

de seu valor quantidade.

Através dos Lançamentos um usuário do sistema pode visualizar a

movimentação da Conta em determinado período de tempo.

Exemplo 1: O Restaurante Universitário comprou 100 Kg de feijão esta semana.

Isso é representado como um Lançamento de 100 na Conta de estoque de feijão do RU.

Exemplo 2: André pagou a prestação de R$ 250,00 de seu carro. Isso é

representado como um Lançamento de –250 na Conta de finanças pessoais de André.

3.2.2 Transações

No padrão Conta tem-se o registro da movimentação de um certo produto em um

estoque ou uma conta. Mas em alguns casos é necessário registrar a movimentação de

um produto de um local para outro. Por exemplo, suponha que uma pessoa tem várias

contas correntes, em bancos diferentes. Neste caso, o padrão Conta não pode registrar a

movimentação de dinheiro entre essas contas.

Uma Transação assume que toda retirada em uma Conta gerará um depósito no

mesmo valor, em outra Conta, e vice-versa. Assim registra-se a origem e o destino de

todas as movimentações (Figura 3.8).

Para explicar o conceito de Transação, Fowler (1997) usa o princípio da

conservação, que diz que o dinheiro (ou qualquer outro produto) nunca é criado ou

destruído e sim movimentado de um local (conta) para outro. Uma Transação contém

uma restrição que diz que a soma de seus lançamentos precisa ser igual a 0 (zero).

Assim o dinheiro é sempre movimentado, nunca criado ou destruído.

29

Figura 3.8 - Transação

Exemplo: Pedro transferiu R$ 1000,00 de sua conta no Banco Brasileiro para sua

conta no Banco Catarinense. Isso é representado por uma Transação com um

Lançamento de -1000 na Conta Banco Brasileiro e outro Lançamento de 1000 na Conta

Banco Catarinense.

Em estruturas mais complexas este padrão é uma boa alternativa ao padrão Conta,

pois além de ter mais informações sobre as movimentações, o princípio de conservação

usado neste padrão ajuda a previnir falhas no sistema.

3.2.3 Transações Múltiplas

O padrão Transação limita-se a representar uma única retirada de alguma Conta e

um único depósito em outra Conta. Assim não há possibilidade de representar a

movimentação de várias Contas em uma única transação.

Por exemplo, se Pedro retirou R$ 1000,00 de sua conta no Banco Brasileiro, e

retirou R$ 1200,00 do Fundo de Ações e depositou o total desse dinheiro na sua conta

do Banco Catarinense, esta movimentação tem de ser representada por duas Transações,

apesar de Pedro ter feito apenas um único depósito na Conta do Banco Catarinense.

Para representar a movimentação de Pedro em uma única Transação usa-se o

modelo de Transações Múltiplas (Figura 3.9).

30

Figura 3.9 – Transação Múltipla

Assim há a possibilidade de se associar dois ou mais Lançamentos a uma

Transação. O princípio da conservação continua valendo neste caso. Assim a Transação

simples (com apenas dois Lançamentos) se torna um caso particular da Transação

Múltipla.

3.2.4 Conta Resumida

Para sistemas de contabilidade um pouco mais complexos, utiliza-se o padrão

Conta Resumida, que faz um agrupamento de várias Contas numa única Conta

Resumida. Este tipo de estruturação pode ser feito conforme o modelo da Figura 3.10

Figura 3.10 – Conta Resumida

31

Exemplo: Na contabilidade de Simão há uma Conta Resumida para gastos

essenciais que agrupa as seguintes Contas Detalhadas: gastos combustível, gastos saúde,

gastos mercado.

Neste modelo apenas, as Contas Detalhadas podem ter Lançamentos. Para calcular

o saldo de uma Conta Resumida, esta consultará as Contas nela agrupadas. Nota-se que

uma Conta Resumida pode agrupar várias Contas Resumidas, criando assim uma árvore

de Contas.

3.2.5 Conta Gatilho

Este padrão teve como base o controle do valor dos impostos sobre movimentação

de dinheiro.

Normalmente, o valor dos impostos de uma empresa só é conhecido quando esta

realiza um balanço no fim do mês, ou do ano. Usando este padrão o sistema irá

contabilizar o valor total do imposto a cada entrada no caixa da empresa.

Ele funciona da seguinte maneira: Para cada Lançamento de entrada de dinheiro

na conta caixa da empresa, haverá também um Lançamento Gatilho em uma outra

conta, uma Conta Gatilho. Este Lançamento Gatilho terá como valor a quantidade de

imposto gerado pelo Lançamento de entrada de dinheiro. Assim, a Conta Gatilho terá no

seu saldo o valor do imposto a ser pago sempre atualizado.

Assim uma empresa pode saber, a qualquer momento, o valor que ela terá que

pagar em impostos de acordo com a movimentação de dinheiro que ela já fez.

Exemplo 1: Quando João recebe o pagamento de um cliente, ele paga 25% deste

pagamento em impostos. João então registra um Lançamento na sua conta de

pagamentos e também um Lançamento na Conta Gatilho Imposto. O Lançamento na

Conta Gatilho será 25% do valor do Lançamento na Conta de João.

32

3.2.6 Regra de Lançamento

No exemplo da Conta Gatilho para imposto, o usuário deve sempre realizar dois

lançamentos no sistema para registrar a taxação da movimentação. Um lançamento para

a conta real e um lançamento registrando o valor da taxação.

Se o imposto tem um valor fixo, como 25% no exemplo anterior, pode-se

programar o sistema para realizar os lançamentos na Conta Gatilho automaticamente,

simplesmente criando uma regra para as contas as quais os lançamentos são taxados.

A regra calcularia o imposto de todos os lançamentos de uma conta associada

como gatilho e geraria um lançamento, no valor calculado, numa Conta Gatilho,

associada à Regra de Lançamento como saída. (figura 3.11).

Figura 3.11 – Regra de Lançamento

Exemplo: Todo pagamento recebido por um serviço é taxado em 12% pelo ISS

(imposto sobre serviços). Modela-se esta taxação com a Conta pagamento de serviços

sendo o gatilho da Regra de Lançamento cálculo de ISS e a saída desta Regra sendo a

Conta total do ISS.

Há casos em que o cálculo do valor do imposto é um pouco mais complexo, e não

apenas uma mera multiplicação. Um exemplo é o cálculo de impostos gradativos, em

que movimentações abaixo de um valor são isentas de cobrança, e acima de outro valor,

tem uma cobrança diferenciada.

Para estes casos é necessário um algoritmo arbitrário para o cálculo do imposto.

Então um Método de Cálculo é associado a classe Regra de Lançamento. Assim cada

instância de Regra de Lançamento terá seu próprio Método de Cálculo (figura 3.12).

33

Figura 3.12 – Metodo de Cálculo para saida

3.2.7 Regras de Lançamentos para várias contas

Pode-se estender o padrão Regra de Lançamento de maneira que uma única regra

possa tratar de várias contas, sem a necessidade de criar uma regra para cada conta do

sistema.

Assim, tomando uma empresa genérica como exemplo, pode-se ter uma Conta

para cada empregado e apenas uma Regra de Lançamento para tratar o cálculo do

imposto de renda sobre o salário dos trabalhadores.

Pode-se modelar a solução de duas maneiras: a primeira é dividir o modelo em

dois níveis: nível de informação e nível operacional. Colocam-se as Regras de

Lançamento no nível de informação e associam-nas com Tipo de Conta. Assim pode-se

ter Tipo de Conta para salário, horas-extras, etc. No nível operacional colocam-se as

contas reais do domínio da aplicação (figura 3.13).

34

Figura 3.13 – Conta e Tipo de Conta

Quando um Lançamento for feito na Conta, esta vai executar as regras de

lançamento do Tipo de Conta associado a ela.

A segunda maneira proposta é usar Contas Resumida (seção 3.2.4). Uma Regra de

Lançamento é definida para uma conta resumo e quando um lançamento é feito em uma

conta detalhada, esta executará a Regra de Lançamento de sua conta resumo.

A escolha entre os dois métodos depende do comportamento do Tipo de Conta.

Caso a divisão de nível de informação e nível operacional seja bem clara, e todas as

regras de lançamento estejam associadas ao Tipo de Conta e os lançamentos só são

feitos em uma conta, então o modelo de níveis é mais apropriado.

Mas em muitos casos os lançamentos podem ser feitos em níveis mais gerais.

Lançamentos podem estar associados a Tipos de Conta e regras de lançamentos

associadas a contas, o que infringiria a divisão entres os níveis operacionais e de

informação. Neste caso o melhor é usar o modelo da segunda proposta, com contas

resumo.

35

Pode-se estender os modelos para abranger situações mais complexas, como casos

em que a conta de saída da regra de lançamento pode mudar de acordo com certos

parâmetros. Como exemplo, tem-se o caso em que o desempenho de um programador

dentro de um projeto afeta o salário do gerente deste projeto. Neste caso, a regra de

lançamento teria a conta desempenho do programador como gatilho, e deve “procurar”

a conta salário do gerente do projeto para colocar como saída. Isso se faz através da

associação da regra de lançamento a um método de procura (figura 3.14).

Figura 3.14 – Localizador de Conta

O método localizador vai consultar a conta gatilho desta regra para saber qual

programador é a fonte deste lançamento. Consultando o programador, o método obtem

informações sobre o projeto deste programador e o seu gerente. Assim o método

localizador encontra a conta salário do gerente, que irá receber um lançamento de bônus

pelo desempenho deste programador.

3.3 Comércio

Neste capítulo serão descritos padrões que realizam o controle de compra e venda

de produtos, e como o valor destes produtos pode modificar as condições do mercado.

Os padrões descrevem como uma instituição pode registrar suas operações comerciais

para usar como base para tomada de decisões.

36

3.3.1 Contrato

O tipo mais simples de relação comercial é de uma entidade (pessoa/organização)

comprando um produto de outra entidade. O produto é qualquer item comercializável,

como por exemplo, sacas de café e toneladas de ferro. Um simples modelo como da

figura 3.15 pode representar essa operação.

Em contrato representa-se uma transação comercial como um Contrato. Um

Contrato pode ser uma compra, uma venda ou qualquer outra transação feita entre

entidades. Ele tem como atributos Quantidade e Preço. O produto a ser comercializado é

representado como um Produto que está associado a Contrato (Figura 3.15).

Figura 3.15 – Contrato com especificação

Exemplo: a UFSC registra a compra de 500 resmas de papel Folhex ao preço de

R$ 8,00 cada, como sendo uma Compra com o Contratante sendo a Folhex Fornecedora

de Papel e o Produto sendo resmas de papel. Preço fica em 8 e quantidade 500.

As operações que serão representadas em Contrato nem sempre precisam ser

especificações do mesmo. Para operações de Compra e Venda, tem-se como alternativa

à especificação a criação de duas associações entre Contrato e Parte (Figura 3.16).

37

Figura 3.16 – Contrato com associações

Este segundo modelo também possibilita que sejam registradas transações com

mais de uma Entidade de ambos os lados (vendedor e comprador).

Exemplo: A UFSC deseja registrar a compra de resmas de papel do Centro

Tecnológico. O sistema da UFSC registraria como um Contrato com Folhex

Fornecedora de Papel como vendedor e o CTC como comprador.

Um modelo mais abrangente utilizando Contratos pode ser definido fazendo a

junção dos dois primeiros modelos. Os dois lados da transação foram definidos como

Contratado e Contratante e as especificações de contrato serão as operações que podem

ser realizadas, com seus devidos comportamentos (Figura 3.17).

Figura 3.17 - Contrato

38

O diferencial destes dois últimos modelos é que os contratos registrados não

precisam necessariamente envolver a Entidade que controla o sistema. Caso seja válido,

pode-se registrar transações comerciais entre Entidades externas ao sistema.

Nota-se a possibilidade de relacionar este modelo com o modelo de Transações do

capítulo anterior. Um contrato de venda, por exemplo, pode ser representado por uma

Transação que faz um Lançamento de um produto na Conta de um comprador e faz

outro Lançamento de dinheiro na Conta de um vendedor.

3.3.2 Portfólio

Raramente considera-se um modelo de contratos sozinho. Tipicamente uma

empresa que gerencia contratos vai analisar um grupo de contratos de um certo tipo para

estimar os riscos em contratos futuros. A seleção dos contratos que serão analisados

pode ser feita pelo tipo de produto comercializado, pela entidade contratante ou por

qualquer outra propriedade relevante de contrato.

Um Portfólio representa este grupo, ou seja, uma coleção de contratos que irão ser

avaliados (figura 3.18).

Figura 3.18 - Portfólio

A seleção dos contratos associados a um Portfólio pode ser feita através de um

método que recebe um Contrato como parâmetro. Caso o método retorne um valor

verdadeiro, o Contrato pertencerá àquele Portfólio (figura 3.19).

39

Figura 3.19 – Seleção de Contratos por método booleano

Outra maneira para a construção da coleção dos contratos que pertencerão a um

portfólio é a implementação de um Seletor de Contratos. Este seletor irá combinar

alguns atributos de Contrato, como contratante, produto, data de início, etc. e os

utilizará para filtrar um grupo particular de contratos. (figura 3.20).

40

Figura 3.20 – Seleção de Contratos por comparação com Seletor

Apesar de ser menos abrangente que um método de seleção, o Seletor de

Contratos é bem mais flexível, podendo ser modificado em tempo de execução apenas

alterando o valor de suas propriedades.

Portfólios podem ser temporários ou persistentes. Porfólios temporários são

criados por demanda. Um filtro é especificado e todas as instâncias de Contrato são

consultadas. Ao fim da utilização, o Portfólio perde a sua coleção de Contratos.

Portfólios persistentes são criados da mesma maneira, mas não são descartados ao

fim de sua utilização. Quando um novo Contrato é criado, este passa pelos filtros dos

Portfólios permanentes. Caso o novo Contrato preencha os requisitos do filtro, é

anexado ao Portfólio.

“Portfólios são úteis em muitos domínios. A característica essencial de um

Portfólio é a de que é um objeto que encapsula um mecanismo de seleção de um grupo

de objetos” (FOWLER, 2000)

4 PADRÕES DE PROJETO

Pode-se definir padrões de projetos como um conjunto de classes de software

que descrevem uma solução comum para determinados tipos de problemas. Essas

classes têm papéis bem definidos e interagem entre si para construir uma solução lógica

que será implementada em uma linguagem de programação.

No decorrer do desenvolvimento do trabalho foi feito um estudo de alguns dos

padrões de projeto do livro Design Patterns de Erich Gamma (1994). Segundo o próprio

Gamma, os padrões descritos em seu livro “são descrições de classes e objetos

comunicantes, que são configuradas para resolver algum problema comum de projeto de

software, dentro de um contexto particular”.

Gamma (1994) classifica os padrões em 3 grupos distintos, levando em conta o

tipo de problema ao qual o padrão se destina: criação, estrutural e comportamental

(creational, structutral and behavioral).

Padrões de criação delegam partes do processo de criação de um objeto para

subclasses ou para outros objetos. Padrões estruturais usam herança para compor as

classes. Padrões comportamentais usam herança para implementar algorítmos e fluxos

de controle.

Os padrões estudados foram o Singleton (criação), Factory Method (criação),

Proxy (estrutural), Facade (estrutural), State (comportamental), Strategy

(comportamental) e Composite (estrutural). Mais a frente será discutida a viabilidade do

uso dos padrões no projeto da aplicação de Controle de Atacado.

4.1 Singleton

O padrão Singleton é usado para assegurar que uma referida classe possa ter

apenas uma instância no sistema e essa instância tenha um ponto de acesso global. Pode

ser usado, por exemplo, num sistema de impressão que contenha apenas um spooler,

42

num sistema operacional, que deve contar apenas um sistema de arquivos ou num

sistema de controle de estoque, que deve ter apenas um caixa.

Neste padrão, a classe de instância única, ou classe Singleton, será responsável

em assegurar que apenas uma instância sua poderá ser criada. Para isso, o construtor

dessa classe deve ser uma operação de classe (static em Java ou C++). O acesso à

instância também se dará através de uma operação de classe.

A classe Singleton faz o encapsulamento da sua instância única, armazenada

num atributo da própria classe. Isso permite total controle de quando e como se dará o

acesso à instância (Figura 4.1).

Figura 4.1 – Estrutura do Padrão Singleton

Para implementar uma classe Singleton em Java, declara-se o construtor como

privativo. O acesso a classe se dará através do método obterInstancia que fornecerá

sempre a mesma instância. Caso nenhuma instância da classe tenha sido criada, o

método cria a instância.

public class Singleton { private static Singleton instancia; private Singleton() {} public static Singleton obterInstancia() { if (instancia == null) { instancia = new Singleton(); } return instancia; }

43

Pode-se usar o padrão Singleton para substituir classes totalmente estáticas

(classes sem instâncias, apenas com métodos estáticos) com a vantagem de o padrão

possibilitar o uso de subclasses da classe estática (classes totalmente estáticas não

podem ter seus métodos sobrescritos, não suportam polimorfismo).

4.2 Factory Method O padrão Factory Method é geralmente utilizado em situações onde a definição do

tipo de objeto a ser criado só é especificada na subclasse de uma classe. A utilização do

Factory Method dá mais flexibilidade a classe por deixar que sua subclasse tome a

decisão de que tipo de objeto será craido.

Pode-se citar o exemplo da classe Desenho para demonstrar a utilização do

Factory Method. A classe abstrata desenho trabalha com os objetos da classe abstrata

FormaGeometrica, que generaliza as classes Circulo, Triangulo e Quadrado. Um

método para da classe Desenho sem o uso do Factory Method ficaria da seguinte forma:

public class desenho { public void desenharCasa() { telhado = new Triangulo(); parede = new Circulo(); telhado.desenhar; parede.desenhar; } }

Esse tipo de implementação torna a classe Desenho pouco extensível. Caso haja

necessidade de criar uma extensão de desenho, como por exemplo DesenhoColorido,

utilizando nessa extensão as classes CirculoColorido, TrianguloColorido, e

QuadradoColorido, o método desenharCasa teria que ser refeito.

O padrão Factory Method torna as extensões da classe Desenho mais simples

utilizando-se de "métodos de criação", ou factory methods, para instanciar as classes

Circulo, Triangulo e Quadrado. Abaixo o método de criação criarForma:

44

public class Desenho { public FormaGeometrica criarForma(forma) { if (forma == "circulo") { r = new Circulo(); } else { if (forma == "triangulo") { r = new Triangulo(); . . . return r; } }

O método desenharCasa fica da seguinte forma

public void desenharCasa() { telhado = criarForma("triangulo"); //não há definição da classe parede = criarForma("quadrado"); //não há definição da classe telhado.desenhar; parede.desenhar; }

Dessa maneira, para estender a classe Desenho para DesenhoColorido, reescreve-

se apenas os métodos de criação.

public class DesenhoColorido extends Desenho { public FormaGeometrica criarForma(forma) { if (forma == "circulo") { r = new CirculoColorido(); //modificacao da extensao da

classe } else { if (forma == "triangulo") { r = new TrianguloColorido(); //modificacao da

extensao da classe .

45

4.2.1 Estrutura

A estrutra do padrão é representada por quatro classes: Produto,

ProdutoConcreto, Criador e CriadorConcreto (figura 4.2).

O Produto define a interface do objeto a ser criado. No exemplo anterior, o

Produto seriam as classes Triangulo, Circulo e Quadrado.

ProdutoConcreto é a extensão da classe Produto. As classes TrianguloColorido é

um ProdutoConcreto de Triangulo.

No Criador é declarado o método criador, ou factory method, que retorna um

objeto da classe Produto. A classe Desenho é um criador e criarForma é o factory

method.

O CriadorConcreto reescreve o método criador para retornar uma instância de

ProdutoConcreto (figura 4.2).

Figura 4.2 – Estrutura do Factory Method

46

4.2.2 Implementação

Como visto no exemplo, a implementação de um Factory Method é

relativamente simples. Na classe Criador o factoryMethod pode ser abstrato, contendo

apenas a assinatura do método. Na classe CriadorConcreto o factoryMethod é

definitivamente implementado, podendo ter como argumento, variáveis que tenham

influência na decisão da classe concreta a ser criada.

Classe Criador:

public abstract class Criador { public Produto factoryMethod(); }

Classe CraidorConcreto:

public class CriadorConcreto extends Criador { public Produto factoryMethod() { return new ProdutoConcreto(); } }

4.3 Proxy O padrão Proxy tem como objetivo “prover um substituto ou ponto de acesso”

(GAMMA, 1994) que fará o controle de acesso a outro objeto. Dessa maneira, pode-se

prorrogar os custos da criação de um objeto até que o mesmo seja realmente utilizado,

ou fazer a representação de um objeto remoto localmente.

Numa aplicação com acesso à banco de dados, uma consulta ao banco pode ser

uma tarefa de alto custo. Um objeto persistente pode ter uma propriedade complexa, que

necessita de várias junções de tabelas para ser obtida. O Proxy evita que a definição de

uma propriedade complexa seja feita na construção do objeto, e prorroga a definição

47

dessa propriedade até que seja realmente necessária. Isto torna todo o trabalho mais

eficiente.

Para isso cria-se um intermediário (proxy) do objeto persistente. O objeto

intermediário terá uma interface em comum com o objeto persistente, além de ter uma

referência para o mesmo (figura 4.3).

Figura 4.3 – Exemplo do Proxy

4.3.1 Implementação

Como foi dito anteriormente, a classe Intermediário terá uma referência para o

objeto real. No caso específico do exemplo, a diferença das classes Intermediário e

PersistenteReal estará no construtor das mesmas. O construtor da classe Intermediário

não fará a consulta para obter propriedadeComplexa.

public class Intermediario implements Persistente { private PersistenteReal real; protected int propriedadeSimples; protected String propriedadeComplexa;

48

protected BD BancoDeDados public Intermediario() { BD = BancoDeDados.obterBanco(); propriedadeSimples = BD.consulta(consultaSimples); } public String obterPropriedadeComplexa() { if (real == null) { real = new PersistenteReal(); } return real.obterPropriedadeComplexa(); }

}

Nota-se que uma instância de Intermediario só inicializa propriedadeSimples.

Quando propriedadeComplexa é requistada, Intermediario faz a criação de uma

instância de PersistenciaReal, e desta instância obtém a propriedadeComplexa.

Caso haja necessidade de consultar a propriedadeSimples de uma grande

quantidade de dados, o uso do Proxy fará com que a tarefa fique muito mais eficiênte.

4.3.2 Estrutura

SujeitoReal é a classe original, que terá um substituto equivalente com uma

interface em comum.

O Proxy é a classe que irá substituir SujeitoReal. Proxy referencia SujeitoReal

e as duas compartilham a mesma interface (figura 4.4).

49

Figura 4.4 – Etrutura do Proxy

Algumas variações do Padrão Proxy são:

Remote proxy - fornece uma representação local para um objeto remoto;

Protection proxy – faz controle de acesso ao objeto real. Útil para quando o

objeto real possui acesso restrito;

Virtual proxy – prorroga criação de objetos com alto custo de criação (exemplo

de classe persistente descrito anteriormente);

4.4 Facade

O objetivo do padrão Facade é unificar em uma interface a manipulação de

vários objetos de um subsistema. Assim, as classes do núcleo de cada subsistema podem

ser modificadas sem que a interface para o cliente seja afetada. Em um conjunto de

subsistemas, isso diminui a interdependência entre os mesmos. Outra consequência de

seu uso é a diminuição da complexidade de utilização dos subsistemas, pois reduz o

número de objetos que precisam ser acessados externamente.

50

Pode-se exemplificar o uso do Facade supondo que o sistema de matrícula e

alocação de salas da UFSC tenha a estrutura mostra na Figura 4.5:

Figura 4.5 – Sem o uso do Facade

O cliente do sistema precisa conhecer várias classes, promovendo um

acomplamento forte entre o sistema e o cliente. Utilizando o padrão Facade, o sistema

fornece uma interface única para o cliente, facilitando a utlização e diminuindo o

acoplamento. No exemplo da Figura 4.6 matricula_aloca é um Facade para o sistema de

alocação e matrícula.

51

Figura 4.6 – Com o uso do Facade

4.4.1 Implementação

A classe Facade deve implementar operações gerais do sistema. O acesso ao

sistema deve ser feito unicamente pela classe Facade.

Implementação sem Facade:

public class Cliente { public void matricularCalouro(Aluno umAluno, Curso curso) { Turma[] turmas1fase = curso.materias1fase(); for (int i = 0; i < turmas1fase.length; I++) { turmas1fase[I].adiciona(umAluno); } curso.adicione(umAluno); } }

52

Usando Facade:

public class Matricula_aloca { public void matricular(Aluno oAluno, Curso oCurso, int fase) { . . . }

Simplificação da classe Cliente:

public class Cliente { Matricula_aloca sistemaMatriculaAloca public void matricularCalouro(Aluno umAluno, Curso curso) { sistemaMatriculaAloca.matricular(umAluno, curso, 1);

} }

4.4.2 Estrutura

O Facade cria uma interface única para todo sistema como mostra a Figura 4.7

Figura 4.7 – Estrutura do Facade

53

4.5 State O Padrão State implementa o conceito de “estado de classe”. Ele permite que

uma classe possua vários estados e que a alteração destes estados possa ser feita em

tempo de execução, mudando também o comportamento da classe.

Exemplo 1: Em uma empresa, várias operações, como calculo de impostos,

dependem da classificação da mesma em micro, pequena ou média empresa. Esta

classificação é feita baseando-se no número de empregados da empresa. Neste caso

pode-se utilizar o padrão State para modelar o sistema como mostra a Figura 4.8:

Figura 4.8 – Padrão State

Cada subclasse de Tipo terá sua própria implementação do calculo do imposto.

Assim empresa repassa esta responsabilidade para uma dessas subclasses. O estado da

empresa pode ser definido toda vez que a propriedade n_empregados for alterada.

54

4.5.1 Estrutura

A classe Contexto representa um objeto real que possui vários estados. Contexto

terá uma instância de um EstadoConcreto que definirá seu estado atual.

A classe Estado define uma interface comum para as implementações dos

estados de Contexto.

Cada classe EstadoConcreto implementa um estado real do Contexto.

Pode-se ver o diagrama da estrutura na Figura 4.9:

Figura 4.9 – Estrutura do State

4.5.2 Implementação

Seguindo o padrão, a classe Empresa (exemplo 1) fica da seguinte maneira:

public class Empresa { public final Tipo Micro = new MicroEmpresa(); public final Tipo Pequena = new PequenaEmpresa(); public final Tipo Media = new MediaEmpresa(); protected n_empregados; private Tipo tipo_empresa;

55

public float calcularImposto() { return tipo_empresa.calcularImposto(); } public void alterar_n_empregados(int n_emp) { if (n_emp > 20) { altere_tipo_empresa(Pequena); } else { if (n_emp > 100) { altere_tipo_empresa(Media); } else { altere_tipo_empresa(Micro); } }

n_empregados = n_emp; } private void altere_tipo_empresa(Tipo tipo_emp) { tipo_empresa = tipo_emp; } }

Nota-se que a classe possui associações com as instâncias que implementam

seus estados.

Quando requisistada uma alteração no atributo n_empregados, o procedimento

altere_n_empregados define o tipo de empresa verificando o argumento n_emp e

chamando a função altere_tipo_empresa.

O padrão State não especifica que classe de sua estrutura deve definir o estado

atual de Contexto. Na implementação a definição foi feita na classe Empresa, pois esta

56

possui o conhecimento do critério de alteração dos estados. Em alguns casos define-se a

alteração do estado nas classes de EstadoConcreto.

4.6 Composite

O padrão Composite é usado em aplicações em que se utiliza composição de

objetos individuais para implementação de objetos mais complexos. Este padrão

permite que a forma de manipulação dos objetos seja a mesma, tanto para objetos

simples como para objetos complexos (compostos).

4.6.1 Estrutura

Figura 4.10 – Estrutura do Composite

A classe abstrata Componente declara uma interface para os objetos da

composição e implementa os comportamentos que são comuns aos objetos simples e

complexos.

57

A classe ComponenteComplexo representa um objeto composto. A associação

filho permite que esta composição seja tanto de objetos simples como de objetos

complexos.

ComponenteSimples representa o objeto simples.

4.6.2 Implementação

A classe abstrata Componente implementa apenas os métodos comuns aos dois

tipos de objetos, definindo o restante dos métodos como abstratos.

A classe ComponenteComplexo implementa os métodos de manipulação dos

“componentes filhos” como inserir, remover e retornarFilho.

public class ComponenteComplexo extends Componente {

private Vector composicao;

public void inserir(Componente filho) {

composicao.add(filho);

}

public Componente retornarFilho(int id) {

return (Componente)composicao.get(id);

}

}

A classe ComponenteSimples não possui associação com nenhum outro

componente e não implementa os métodos de manipulação de “filhos”.

58

4.7 Strategy

O padrão Strategy cria a possibilidade de se definir mais de um tipo de algorítmo

para um mesmo método. É útil nos casos onde a implementação do método depende de

algum fator externo à classe em que será implementado.

4.7.1 Estrutura

O padrão será aplicado a uma classe Contexto. Os diferentes algorítmos serão

implementados em diferentes classes, mas com uma interface comum (Estratégia) como

mostra a Figura 4.11:

Figura 4.11 – Estrutura do padrão Strategy

4.7.2 Implementação

Pode-se exemplificar a aplicação do Strategy na implementação de script para

visualização em browsers. Apesar da padronização, browsers como Internet Explorer e

Mozilla interpretam scripts de forma diferente. Usa-se o padrão para implementar

diferentes algoritmos de acordo com o browser.

59

Figura 4.12 – Estrutura do Strategy

public class PaginaWeb { private Script script; public PaginaWeb() { if (navigator.name == "IE") { script = new ScriptIE(); } else { script = new ScriptMozilla(); } } public PaginaWeb(Script novoScript) { script = novoScript; } public void desenhaPopUp() { script.implementaPopUp(); } }

5 MAPEAMENTO DE PADRÕES DE ANÁLISE PARA

PADRÕES DE PROJETO

Um dos objetivos do trabalho é a elaboração de mapeamentos de padrões de

análise para padrões de projeto. Isto é, após estudo aprofundado de um padrão de

análise, o seu modelo conceitual é transformado em um diagrama de classes de projeto

utilizando padrões de projeto. Neste capítulo estão descritos alguns mapeamentos que

foram desenvolvidos durante o trabalho.

5.1 Padrão de Análise Transações e Padrão de Projeto Proxy.

O primeiro projeto refere-se ao mapeamento do padrão de análise Transações

para o padrão de projeto Proxy.

O padrão Proxy se aplica ao modelo de Transações quando as transações são

armazenadas em uma base de dados. Muitos clientes da classe Conta acessarão esta para

consultar somente seu atributo saldo. Nestes casos, não é necessário que Conta tenha

referência para as instâncias da classe Lançamento associadas.

Utiliza-se então o padrão Proxy para que as intâncias da classe Lançamento

sejam carregadas e criadas por demanda.

61

Figura 5.1 – Estrutura do Proxy

Um cliente que necessite somente da consulta do saldo de uma conta irá ter

acesso a uma instância da classe ContaProxy. Esta instância irá carregar apenas o

atributo saldo através da camada de persistência para o banco de dados, prorrogando o

carregamento das instâncias de Lançamento somente quando forem necessárias.

Assim a implementação de calcularSaldo fica da seguinte maneira:

Public float calcularSaldo() { If (real == null) { real = new ContaReal(); } return real.calcularSaldo(); }

5.2 Padrão de Análise Conta Resumida e Padrão de Projeto Composite

Este mapeamento toma como base o padrão de análise Conta projetado pelo

padrão Composite.

62

Figura 5.2 – Padrão de Análise Conta Resumida

Figura 5.3 - Padrão de Projeto Composite

O conceito de Conta será implementado como a classe Componente do padrão

Composite. ContaResumida será o objeto composto do padrão, ou seja, o

ComponenteComplexo. ContaDetalhada será o objeto simples, ou a classe

ComponenteSimples. O diagrama de classe do mapeamento é descrito na Figura 5.4.

63

Figura 5.4 – Diagrama de classe do mapeamento

A implementação segue as regras do padrão Composite. Conta é uma classe

abstrata, mas implementa os métodos comuns à ContaDetalhada e à ContaResumida

como obterSaldo. Conta também define o atributo saldo comum as duas classes. Em

ContaResumida há um método particular, calcularSaldo. Este método deve consultar o

saldo de todos os objetos de Conta associados ao objeto ContaResumida, que podem,

pos sua vez, serem contas detalhadas ou contas resumidas. A implementação segue

abaixo.

Public float calcularSaldo() { Conta _conta; While (agrupadas.hasNext()) { _conta = agrupadas.next(); this.saldo = this.saldo + _conta.obterSaldo(); } return saldo; }

64

5.3 Padrão de Análise Portfólio e Padrão de Projeto Strategy

O padrão de análise Portfólio (seção 4.6.2) consiste em uma coleção de contratos

que obedecem a certos critérios de seleção. Uma das maneiras abordadas para a

construção desta coleção é através de um método de seleção que recebe um contrato

como parâmentro. Caso este método retorne um valor verdadeiro, o contrato será

associado ao Portfólio (figura 5.5).

Figura 5.5 – Seleção de contrato por método

A utilização do padrão Strategy para implementação do Método de Seleção do

Portfólio possibilita a utilização de vários métodos de seleção distintos, e a escolha de

que método de seleção será utilizado pelo Portfólio para seleção de contratos pode ser

feita por externamente à classe, dando grande flexibilidade ao sistema.

A seguir, tem-se o diagrama de classes de um Portfólio projetado usando-se

Strategy.

65

Figura 5.6 – Estrutura da implementação

A implementação da classe Contrato fica da seguinte forma:

public class Portfolio { protected MetodoSelecao filtro; public selecionarMetodo(String selecao) { if (selecao == "porValor") { filtro = new SelecaoValor(); } else { filtro = new SelecaoData(); } } public void analisar() { Contrato contrato; while selecao.hasNext() { contrato = selecao.next(); if (filtro.filtrar(contrato) == false) { selecao.remove(contrato); } } }

66

No exemplo acima o método selecionarMetodo recebe um parametro selecao

que define qual método de seleção será usado pela instância de Portfolio.

5.3.1 Uso do Singleton

De acordo com o padrão de análise Portfólio, um mesmo método de seleção

pode ser usado por vários portfólios. Neste caso pode-se evitar o custo da criação de

várias instâncias de MétodoSeleção implementando-se as classes concretas dos métodos

de seleção como Singletons.

Assim tem-se o mapeamento do padrão de análise Portfólio para os padrões de

projeto Singleton e Strategy (figura 5.7).

Figura 5.7 – Portfólio mapeado para Singleton e Strategy

Abaixo segue a implementação da classe SelecaoValor como um Singleton: public class SelecaoValor implements MetodoSelecao { protected SelecaoValor(){} public boolean filtrar(Contrato contrato){ }

67

public static SelecaoValor obterInstancia(){ if (instancia == null) { instancia = new SelecaoValor(); } return instancia; } private static SelecaoValor instancia = null; }

5.4 Padrão de Análise Regra de Lançamento e Padrão Strategy

Em um caso semelhante ao anterior, o padrão de análise Regra de Lançamento

possui um método para cálculo do valor do lançamento que será efetuado na sua Conta

de saída (figura 5.8). Para flexibilizar a classe de Regra de Lançamento, também faz-se

usar do padrão Strategy na sua implementação.

Figura 5.8 – Padrão de análise Regra de Lançamento

Figura 5.9 – Mapeamento do Padrão Regra de Lançamento para o Strategy

68

A implementação da classe RegraLancamento segue abaixo:

public class RegraLancamento { protected Conta saida; protected MetodoCalculo calculo; public alterarSaldo(float saldo) { if (saldo > 1000) { calculo = new MetodoCalculoA(); } else { calculo = new MetodoCalculoB(); } } public void calcular() { saida.lanca(calculo.calcular()); } }

O metodo alterarSaldo de RegraLancamento recebe saldo como parâmetro, e a

partir dele decide que método de cálculo será usado.

6 DESENVOLVIMENTO

O objetivo final do trabalho é desenvolver um modelo de análise e de projeto e

implementar uma aplicação fazendo uso de alguns padrões estudados durante a fase de

pesquisa. Neste capítulo será descrito como os padrões estudados foram utilizados no

processo de desenvolvimento da aplicação de controle de atacado.

6.1 Levantamento de Requisitos

6.1.1 Descrição do Domínio da Aplicação

O domínio desta aplicação é a consignação e venda de produtos. A empresa que

serviu de base para o desenvolvimento é um atacado de jóias. Lá são vendidos vários

tipos de jóias e semijóias, além de relógios, embalagens e mostruários.

A maioria dos clientes da joalheria trabalha com produtos consignados. O

processo de consignação se dá da seguinte maneira: um consignador (cliente da

empresa) vai até a empresa e retira alguns produtos para levar em consignação. Este

vendedor tem um período para vender os produtos (fora da empresa). Após este período

ele retorna à empresa, e realiza o fechamento: faz o pagamento dos produtos que foram

vendidos e faz a devolução dos produtos que não conseguiu vender.

A empresa também faz vendas sem consignação. Ou seja, um cliente vem até a

empresa e faz a compra de um produto diretamente, sem consigná-lo.

Além de controlar a parte de consignação e venda, o software deve fazer o

controle de estoque, fluxo de caixa, e geração relatórios gerais (lucro, gastos, estoque

etc.).

O estoque fica dividido em produtos que estão no estoque da empresa e produtos

consignados.

70

Como fluxo de caixa, o sistema deve registrar os pagamentos aos fornecedores, o

recebimento de contas a prazo (promissórias e cheques) e os gastos administrativos da

empresa.

6.1.2 Casos de Uso

A seguir a descrição dos casos de uso p/ aplicação. Caso de Uso: Consignar Produtos Atores: Funcionário.

Tipo: Primário

Descrição: O cliente escolhe os produtos que deseja levar em consignação. O

funcionário registra os produtos em poder do cliente.

Seqüência Típica de Eventos Ação do Ator Resposta do Sistema

1- O funcionário se identifica através

do código do funcionário.

2- O funcionário identifica o cliente

através do código do cliente.

3- O sistema informa os dados do

cliente (nome, telefones, RG, CPF,

endereço) e os produtos consignados (código

do produto, nome do produto, quantidade),

caso ele tenha alguma.

4- O funcionário identifica os

produtos escolhidos pelo cliente através dos

códigos dos produtos.

Caso haja mais de um produto do

mesmo tipo, o funcionário entra também

com a quantidade.

5- O sistema informa o valor total

dos produtos e o valor mínimo que deve ser

vendido para alcançar a meta de venda.

71

6- O funcionário confirma a

operação.

7- O sistema imprime um relatório

contendo o código e nome do cliente; nome

do funcionário que realizou a operação;

código, nome, quantidade, valor unitário e

valor total dos produtos consignados na

operação.

Seqüências Alternativas

1.1 – O código do funcionário é inválido. Cancelar a operação.

2.1 – O código do cliente é inválido (não está cadastrado). Cancelar a operação e

perguntar ao usuário se deseja cadastrar o cliente (caso de uso Cadastrar Cliente).

4.1 – O código do produto é inválido (não está cadastrada). Perguntar ao usuário

se deseja cadastrar o produto (caso de uso Cadastrar Produto).

Caso de Uso: Fazer Fechamento

Atores: Funcionário.

Tipo: Primário

Descrição: O cliente informa os produtos que foram vendidos e os produtos que

serão devolvidos. O funcionário registra os produtos devolvidos e,

consultando o registro de produtos em poder do cliente, informa o

débito do cliente. Este faz o pagamento à vista ou escolhe formas de

pagamento a prazo.

72

Seqüência Típica de Eventos

Ação do Ator Resposta do Sistema

1- O funcionário se identifica através

do código do funcionário.

2- O funcionário identifica o cliente

através do código do cliente.

3- O sistema informa os dados do

cliente (nome, telefones, RG, CPF,

endereço) e seus produtos consignados

(código do produto, nome do produto,

quantidade).

4- O funcionário seleciona dentre os

produtos consignados ao cliente, quais serão

devolvidos, caso haja devolução.

5- O sistema informa o valor total

dos produtos devolvidos e o valor total dos

produtos comprados pelo cliente.

5- O funcionário registra a forma de

pagamento escolhida pelo cliente – avista ou

a prazo.

Na forma de pagamento a prazo deve

ser identificado se será usado cheque ou

promissória.

6- Se a forma de pagamento a prazo

for escolhida o sistema mostra o valor das

prestações.

7- O cliente faz o pagamento (se for o

caso) e o funcionário confirma a operação.

8- O sistema imprime um relatório

contendo código e nome do cliente; nome do

funcionário que realizou a operação; código,

nome, quantidade, valor unitário e valor total

dos produtos vendidas na operação.

Seqüências Alternativas

1.1 – O código do funcionário é inválido. Cancelar a operação.

4.1 – O cliente deseja devolver mais produtos que o permitido pela meta de

vendas. O gerente entra com o código do gerente para permitir a devolução.

73

Caso de Uso: Comprar Produtos

Atores: Funcionário

Tipo: Primário

Descrição: O fornecedor é identificado e os produtos são comprados. É feito o

pagamento à vista ao fornecedor, ou escolhe-se formas de

pagamento a prazo.

Seqüência Típica de Eventos

Ação do Ator Resposta do Sistema

1- O funcionário se identifica através

do código do funcionário.

2- O funcionário identifica o

fornecedor através do código do fornecedor.

3- O sistema informa os dados do

fornecedor (nome, telefones, RG, CPF,

endereço)

4- O funcionário registra os produtos

que serão comprados no sistema, informando

código, descrição e preço de compra.

5- O sistema informa o total da

compra.

6- O funcionário escolhe a forma de

pagamento – à vista ou à prazo.

Na forma de pagamento a prazo deve

ser identificado se será usado cheque ou

promissória (carnê).

7- O sistema imprime um relatório

contendo código e nome do fornecedor;

nome do funcionário que realizou a

operação; código, nome, quantidade, valor

unitário e valor total dos produtos

comprados na operação.

Seqüências Alternativas

1.1 – O código do funcionário é inválido. Cancelar a operação.

2.1 – O código do fornecedor é inválido. Cancelar a operação e dispara caso de

uso Cadastrar Fornecedor.

74

Caso de Uso: Vender Produtos

Atores: Funcionário.

Tipo: Primário

Descrição: O funcionário apresenta os produtos ao cliente. O cliente escolhe os

produtos e faz o pagamento, ou escolhe formas de pagamento a

prazo.

Seqüência Típica de Eventos

Ação do Ator Resposta do Sistema

1- O funcionário se identifica através

do código do funcionário.

2- O funcionário identifica o cliente

através do código do cliente.

3- O sistema informa os dados do

cliente (nome, telefones, RG, CPF,

endereço) e seus produtos consignados

(código do produto, nome do produto,

quantidade).

4- O funcionário identifica os

produtos escolhidos pelo cliente através do

código do produto.

Caso haja mais de um produto do

mesmo tipo, o funcionário entra também

com a quantidade.

5- O sistema informa o valor total

dos produtos

6- O funcionário registra a forma de

pagamento escolhida pelo cliente – a vista

ou a prazo.

Na forma de pagamento a prazo deve

ser identificado se será usado cheque ou

promissória.

7- Se a forma de pagamento a prazo

for escolhida o sistema mostra o valor das

prestações.

75

8- O cliente faz o pagamento (se for o

caso) e o funcionário confirma a operação.

9- O sistema imprime um relatório

contendo código e nome do cliente; nome do

funcionário que realizou a operação; código,

nome, quantidade, valor unitário e valor total

dos produtos vendidas na operação.

Seqüências Alternativas

1.1 – O código do funcionário é inválido. Cancelar a operação.

2.1 – O código do cliente é inválido (não está cadastrado). Cancelar a operação e

perguntar ao usuário se deseja cadastrar o cliente (caso de uso Cadastrar Cliente).

4.1 – O código do produto é inválido (não está cadastrada). Disparar caso de uso

Cadastrar Produtos.

Caso de Uso: Vender Produtos à Vista

Atores: Funcionário.

Tipo: Primário

Descrição: O funcionário apresenta os produtos ao cliente. O cliente escolhe os

produtos e faz o pagamento a vista. Neste caso de uso o cliente não

é identificado.

Seqüência Típica de Eventos

Ação do Ator Resposta do Sistema

1- O funcionário identifica-se através

do código do funcionário.

2- O funcionário identifica os

produtos escolhidos pelo cliente através do

código do produto.

Caso haja mais de um produto do

mesmo tipo, o funcionário entra também

com a quantidade.

3- O sistema informa o valor total

dos produtos

76

4- O cliente faz o pagamento (se for o

caso) e o funcionário confirma a operação.

Seqüências Alternativas

2.1 – O código do produto é inválido (não está cadastrada). Disparar o caso de

uso Cadastrar Produtos.

Caso de Uso: Fazer Pagamento ao Fornecedor

Atores: Funcionário

Tipo: Primário

Descrição: O pagamento é feito ao fornecedor e o débito é eliminado

Seqüência Típica de Eventos

Ação do Ator Resposta do Sistema

1- O funcionário identifica o

fornecedor através do código do fornecedor.

2- O sistema exibe a lista de débitos

com o fornecedor identificado.

3- O funcionário escolhe o

pagamento dentre a lista de débitos.

4- O sistema imprime um recibo

contendo o nome do fornecedor e o valor do

pagamento.

Caso de Uso: Receber Pagamento

Atores: Funcionário

Tipo: Primário

Descrição: O cliente faz o pagamento e seu débito é liquidado.

77

Seqüência Típica de Eventos

Ação do Ator Resposta do Sistema

1- O funcionário identifica o cliente

através do código do cliente.

2- O sistema exibe a lista de débitos

do cliente identificado (nome do cliente, data

e valor do débito).

3- O funcionário escolhe qual débito

será liquidado.

4- O sistema imprime um recibo

contendo o nome do cliente e o valor do

pagamento.

Seqüências Alternativas

3.1 – O cliente paga um valor inferior ao valor do débito. O gerente entra com o

código do gerente e o débito é alterado com o novo valor (valor da dívida – valor pago).

Caso de Uso: Definir Meta de Venda

Atores: Gerente

Tipo: Secundário

Descrição: O gerente define a porcentagem de produtos consignados que deve

ser vendidas, ou seja, que não podem ser devolvidas.

Seqüência Típica de Eventos

Ação do Ator Resposta do Sistema

1- O gerente define a porcentagem de

produtos consignados que deve ser vendidas

(não pode ser devolvidas) para todos os

clientes.

2- O gerente confirma a operação

78

Caso de Uso: Fazer Pagamento Administrativo

Atores: Funcionário

Tipo: Secundário

Descrição: O funcionário descreve um gasto administrativo e fornece seu valor.

Seqüência Típica de Eventos

Ação do Ator Resposta do Sistema

1- O funcionário identifica-se através

do código do funcionário.

2- O funcionário descreve o gasto

administrativo e fornece o valor.

Caso de Uso: Cadastrar Cliente

Atores: Funcionário

Tipo: Primário

Descrição: Cadastra um cliente.

Seqüência Típica de Eventos

Ação do Ator Resposta do Sistema

1- O funcionário preenche um

cadastro com os dados do cliente (nome,

telefone, RG, CPF, data de nascimento,

endereço)

2- O funcionário confere os dados e

confirma a operação.

79

Caso de Uso: Cadastrar Produto

Atores: Funcionário

Tipo: Primário

Descrição: Cadastra umo produto.

Seqüência Típica de Eventos

Ação do Ator Resposta do Sistema

1- O funcionário preenche um

cadastro com os dados do produto

(descrição, quantidade, preço)

2- O funcionário confere os dados e

confirma a operação.

80

6.2 Análise

Como descreve Craig Larman (1997) “Para criar o software de uma aplicação, é

necessário uma descrição do problema e dos seus requisitos”. A análise nada mais é do

que a transformação dos requisitos da aplicação em especificações que descreverão uma

solução lógica para o domínio do problema.

Nesta fase procura-se pesquisar e entender o domínio do problema, a partir da

descrição dos requisitos, para o desenvolvimento de um modelo conceitual. É o que

Craig Larman (2001) chama de “investigação do problema”.

6.2.1 Modelo Conceitual

A palavra modelo pode ser definida como “uma representação abstrata que

permite descrever e/ou prever comportamentos específicos de um sistema, através do

estudo de um número reduzido de características relevantes do sistema” (MAFFEO,

1992) Esta representação pode ser de um fenômeno do mundo real (as leis físicas de

movimento são um modelo do movimento no mundo real), de uma máquina ou de um

software. Os resultados dos processos de análise serão modelos do domínio da aplicação

que está sendo desenvolvida.

O modelo conceitual “ilustra os conceitos significativos em um domínio de

problema” (LARMAN, 1997). Ele é um resultado da fase de análise e será a base para a

fase de projeto.

A partir da análise dos casos de uso e dos requisitos, decompõe-se o “problema em

conceitos e objetos individuais” (LARMAN, 1997). Nesta parte do desenvolvimento

ocorre a elaboração de um modelo conceitual do problema.

No modelo da análise não se descreve artefatos de implementação de software

como classes de interface com o usuário ou camadas de persistência. O objetivo do

modelo conceitual não é ser um projeto de software, mas uma descrição de coisas do

mundo real que fazem parte do domínio do problema e sua solução.

“Modelos não são certos ou errados, eles são mais ou menos úteis” (FOWLER,

1997). A escolha do modelo terá conseqüências na flexibilidade e reusabilidade do

81

projeto. Por isso, um estudo aprofundado do domínio é importante antes de iniciar a

modelagem.

No modelo conceitual do controle de atacado a classe Atacado representa a

empresa proprietária. Os clientes do atacado são representados pela classe Cliente. Os

fornecedores são representados pela classe Fornecedor. Atacado, Cliente, Fornecedor e

Funcionário são especificações de Entidade, pois representam conceitos de

pessoa/organização (figura 6.1).

Figura 6.1 – Modelo baseado no padrão Entidade

A consignação, compra e venda de produtos, descrita nos casos de uso de Compra

de Produtos, Venda de Produtos e Consignação de Produtos são representadas através

82

das classes Compra, Venda e Consignação. Toda venda e toda consignação são feitas do

atacado para um cliente. Então associou-se o Cliente à Consignação e à Venda. Uma

compra é sempre feita de um fornecedor. Assim associou-se Compra à Fornecedor

(figura 6.2).

Figura 6.2 – Modelo sem conceito de Contrato

Nota-se que as classes de operação Venda, Consignação e Compra estão

associadas sempre à duas entidades, sendo uma das entidades o Atacado. Assim sendo,

baseou-se no padrão Contratos, que diz que “Um Contrato pode ser uma compra, uma

venda ou qualquer outra transação feita entre entidades”, para generalizar as três

operações em uma classe Contrato como descrito na figura 6.3.

83

Figura 6.3 – Conceito de Contrato

A data_fechamento de Consignação é a data em que o cliente devolve os produtos

que levou consignado como descrito no caso de uso consignar produtos.

A classe Contrato está associada ao Atacado, pois as operações de compra, venda

e consignação sempre tem o atacado como parte contratada. Contrato também é

associado a um Funcionário, o qual irá iniciar o contrato no sistema. Finalmente tem-se

a associação de Contrato com Produto, pois as operações realizam a comercialização de

produtos do atacado (figura 6.4).

84

Figura 6.4 – Modelo com conceito de Contrato

O padrão Conta Resumida foi utilizado para elaborar o controle de caixa do

sistema. A classe Caixa, uma Conta Resumida, irá representar o caixa da empresa, tendo

como Contas Detalhadas a conta Receita e a conta Despesa. Lançamentos feitos em

Receita representam entrada de dinheiro na empresa. Lançamentos feitos em Despesa

representam os gastos. O atributo saldo de Caixa será diferença entre as receitas e as

despesas da empresa.

85

Figura 6.5 – Conta Caixa, Receita e Despesa

Toda Venda e toda Compra gerará um ou mais Lançamentos. A classe Atacado

também pode gerar Lançamentos que serão referentes a despesas administrativas como

pagamentos de salário, compra de material de escritório, etc. (figura 6.6).

86

Figura 6.6 – Lançamentos nos Caixas

Em Lançamento o atributo valor representa o valor do lançamento em reais. O tipo

de lançamento pode ser cheque, promissória ou dinheiro. A data_lançamento será a data

em que o lançamento será contabilizado no sistema. A data_registro é a data em que o

lançamento foi inserido no sistema. Por exemplo, um pagamento com cheque para 30

dias feito no dia 1º de maio será registrado como um Lançamento do tipo cheque com

data_registro 01/05 e data_lançamento 31/05.

O modelo completo está descrito na figura 6.7.

87

Figura 6.7 – Modelo conceitual da aplicacao

88

6.3 Projeto

O projeto do software é a definição de quais artefatos de software serão usados

na implementação de uma solução lógica para o problema. E “como eles (os artefatos)

irão colaborar para preencher todos os requisitos” (LARMAN, 2001).

Os artefatos do projeto serão criados com base na inverstigação feita na fase de

análise.

“Seu projeto precisa ser específico para resolver o problema, mas também

suficientemente flexível para tratar problemas e requisitos que surgirem no futuro”

(GAMMA, 1994). Projetistas iniciantes dificilmente conseguem um bom projeto de

software. Um projeto ruim precisa ser alterado toda vez que surge um novo requisito, ou

se encontra algum problema.

Projetistas exprientes conseguem fazer um bom projeto utilizando suas

experiências anteriores. Quando um problema de projeto é solucionado, esta solução é

registrada, para que no futuro, quando surgir um problema igual ou semelhante, não seja

necessário dispender tempo desenvolvendo um novo projeto. Assim nasce um padrão de

projeto.

6.3.1 Linguagem e Banco de Dados

A linguagem escolhida para o desenvolvimento da aplicação foi Java. Os fatores

que influenciaram na escolha foram sua natureza multi-plataforma, robustez e relativa

facilidade de programação (quando comparada com C++).

Como a aplicação a ser desenvolvida utiliza objetos persistentes, fez-se

necessário o estudo de um sistema gerenciador de banco de dados (SGBD).

Um fator preponderante na escolha do SGBD foi a portabilidade, pois a

aplicação desenvolvida utiliza linguagem Java, que tem portabilidade como uma das

caracterísiticas principais.

Outro fator foi o custo do software. Os SGBDs mais populares normalmente

exigem altos custos para sua aquisição. Neste trabalho pretende-se desenvolver uma

aplicação de baixo custo, que poderá ser utilizada em um sistema operacional gratuito,

89

como Linux. Isso possibilita que os usuários da aplicação arquem com os custos apenas

de equipamento e treinamento.

Levando em conta os fatores descritos acima, escolheu-se o Firebird como

SGBD da aplicação a ser desenvolvida. O Firebird é um banco de dados relacional de

código aberto que deriva do Interbase. O Interbase também é um SGBD freeware

pertencente a Borland. Apesar de ser freeware, o Interbase é um projeto com direções

mais comerciais.

O Firebird se mostrou um banco de dados estável. Oferece suporte a triggers e

stored procedures. A versão usada foi a 1.5 ClassicServer (IBPHOENIX, 2004).

A instalação do Firebird não inclui interface gráfica para manipulação de dados.

Mas interfaces são encontradas facilmente na Internet, principalmente porque a maioria

das interfaces para Interbase são compatíveis com o Firebird.

Iniciou-se o trabalho usando o IBAccess, que se mostrou muito limitada e

instável. Na procura de uma interface mais robusta, encontrou-se o IBExpert, que

mesmo na versão mais simples (Personal) possui vários recursos que ajudam a tirar

proveito de todas as funcionalidades do banco de dados Firebird.

6.3.2 Diagramas de Sequência

Das ferramentas UML para descrição de um projeto de software, duas serão

utilizadas para o desenvolvimento da aplicação de Controle de Estoque: os diagramas de

sequência que descreve “como os objetos interagem via menssagens” (LARMAN,

2001) e o diagrama de classe, que descreve as classes do projeto e suas associações.

Dando continuidade a fase de projeto, foram criados diagramas de interação para

os casos de uso correspondentes. Os diagramas de interação mostram “como os objetos

interagem através de mensagens para cumprir tarefas.” (LARMAN, 1997).

Os diagramas de interação podem ser representados através de dois tipo distintos:

diagramas de colaboração, que representam a interação entre os objetos do software

através de um grafo, e diagramas de sequência. A seguir tem-se os diagramas de

sequência para os casos de uso mais relevantes do sistema.

90

6.3.2.1 Consignar

O diagrama de sequência de consignar que representa o caso de uso Consignar

Produto é descrito na Figura 6.8.

Figura 6.8 – Diagrama de Sequência Consignar

91

6.3.2.2 Vender

Diagrama de Sequência do Caso de Uso Vender Produto descrito na Figura 6.9.

Figura 6.9 – Diagrama de Sequência Vender

92

6.3.3 Diagrama de Classes

Em paralelo com a criação dos diagramas de colaboração é feita a elaboração do

diagrama de classes de projeto. Utilizando como base os métodos e relações

encontrados nos diagramas de sequência, o diagrama de classes vai descrever as classes

do projeto, seus métodos, atributos e associações. Diferente do modelo conceitual, o

diagrama de classes “mostra definições de classes de software em vez de conceitos do

mundo real” (LARMAN, 2001).

6.3.3.1 Contratos

No projeto a classe Contrato foi implementada como abstrata. Esta classe

implementa o comportamento comum de suas subclasses Venda, Compra e

Consignação. A classe Contrato também possui uma associação com Produtos. Ao

carregar um objeto de Contrato do banco de dados, todas as instâncias de Produtos

associadas a este Contrato serão carregadas e instânciadas. Isso cria um problema de

desempenho caso várias instâncias de Contrato precisem ser carregadas, por exemplo,

para geração de relatórios.

Para solucionar este problema, foi utilizado o padrão Proxy na implementação

de Contrato e suas subclasses. Assim duas classes podem representar um contrato:

ContratoReal e ContratoProxy. A classe ContratoProxy não carrega as instâncias de

Produto na sua criação, eliminando o problema de desempenho nas operações que

necessitam consultar apenas propriedades da classe Contrato. Uma interface Contrato

foi criada para interfacear as classes ContratoReal e ContratoProxy.

93

Figura 6.10 – Contrato com Proxy

O padrão Proxy descrito por Gamma (1994) não prevê herança no uso do Proxy.

Como Contrato tem subclasses, houve a necessidade de estender o padrão para estas

classes. Para isso aplicou-se o padrão as subclasses de Contrato. Assim cada

participante de Proxy especializa a superclasse que representa o mesmo papel, como

segue abaixo:

94

Figura 6.11 – Heranças de contrato com Proxy

6.3.3.2 Conta Caixa

Como o padrão de análise Conta Resumida (seção 3.2.4) foi aplicado para

modelar o controle de caixa, e no mapeamento de padrões de análise para padrões de

projeto desenvolveu-se o mapeamento do padrão Conta Resumida para o padrão

Composite (seção 6.2), projetou-se o controle de caixa fazendo uso desse mapeamento.

95

Figura 6.12 – Conta Resumida projetada para Caixas

Assim Caixa é uma ContaResumida que irá agrupar uma instância de Receita e

uma instância de Despesa. Obedecendo ao padrão Composite todas as classes

implementam uma interface comum, que neste caso é a interface Conta.

Como neste caso a empresa terá apenas um caixa, implementou-se a classe

Caixa como um Singleton. O atributo caixa é implementado como atributo de classe e o

método obterCaixa é implementado como métodos de classe (static). O mesmo é valido

para as classes Receita e Despesa.

96

6.3.3.3 Camada de Persistência

Como a aplicação utiliza-se de banco de dados para tornar seus objetos

persistentes, houve a necessidade de se implementar uma camada de persistência.

A camada de persitência desenvolvida consiste de uma coleção de mapeadores

de classe. Cada classe persistente do sistema possui um mapeador na camada de

persistência. O mapeador tem as informações de como uma instância da classe é

armazenada no banco de dados, e implementa as querys SQL para armazenar um objeto

no banco, carrega-lo no sistema, fazer alterações, etc.

Todos os mapeadores tem uma interface comum, com métodos como

carregar(int id), salvar(Object objeto), existe(int codigo).

Seguindo o padrão Facade (seção 5.6), criou-se uma classe que serve de

interface de comunicação da camada de aplicação com todos os mapeadores da camada

de persistência. Esta classe, chamada de Persistência, também é responsável pela

criação da conexão com o sistema de banco de dados. Caso o sistema de banco de dados

da aplicação seja alterado, a classe Persistência é a única a sofrer alteração na sua

implementação.

Como a aplicação possui somente um banco de dados, a classe Persistência foi

implementada como um Singleton.

97

Figura 6.13 – Camada de Persistencia

98

6.4 Implementação

Com os artefatos UML gerados na fase de projeto, tem-se uma base para o início

da fase de implementação da aplicação. Nesta fase, os artefatos UML são transformados

em código de alguma linguagem de programação.

Para implementação desta aplicação a linguagem de programação escolhida foi

Java. O ambiente de programação utilizado foi o NetBeans IDE 3.5.1.

A seguir serão detalhados alguns métodos que merecem atenção.

6.4.1 Método Vender

O caso de uso vender é implementado pelo método vender da classe Atacado.

Baseando-se no diagrama de sequência, este método recebe como parâmetro o código

do funcionário, código do cliente, um vetor com os códigos dos produtos vendidos, um

vetor com as quantidades de cada produto e o número de produtos. Os parâmetros

código do funcionário e código do cliente não serão utilizados no protótipo. Abaixo

segue a assinatura do método:

Public void vender(int codigoFun, int codigoCliente, int[] codigoProdutos, int[] quantidades, int Produtos)

O método vender carrega as informações do banco de dados através da

referência que atacado têm à classe Persistência. Através do método carregar, todos os

produtos cujo código está no vetor codigoProdutos serão carregados para uma instância

da classe Vector (classe da biblioteca Java que implementa um array dinâmico).

Vector vetorProdutos = bd.carregar(codigoProdutos, Produto.class, nProdutos);

Após o carregamento, é executado o método vender para todas as instâncias da

classe Produto armazenadas em vetorProdutos. O método vender, da classe Produto,

recebe como parâmetro a quantidade de produtos vendidos. Este método diminui a

quantidade passada como parâmetro do atributo quantidade da instância (faz a retirada

99

do estoque), e retorna uma instância clone do produto.O valor do atributo quantidade

deste clone tem o mesmo valor do parâmetro quantidade passado para o método (o

clone representa o produto vendido). Abaixo segue o método vender da classe Produto.

public Produto vender(int qtd) { Produto prodVendido; prodVendido = this.clonar(); prodVendido.quantidade = qtd; this.quantidade = this.quantidade - qtd; return prodVendido; }

Os produtos fornecidos pelo método vender, da classe Produto, são armazenados

em uma instância da classe Vector, chamada vetorProdVendidos. Esse vetor é passado

como argumento para uma instância da classe VendaReal, que vai registrar a operação

de venda. Essa instância de VendaReal é então salva no banco de dados. Os produtos os

quais as quantidades foram alteradas (instâncias de Produto as quais o método vender

foi executado) também são salvos no banco.

VendaReal venda = new VendaReal( 0, 0, vetorProdVendido); bd.salvar(venda); bd.salvar(vetorProdEstoque);

6.4.2 Método obterVendas

O método obterVendas da Classe atacado carrega todas as vendas registradas no

banco de dados. Para melhorar o desempenho, este método faz uso de objetos Proxy de

Vendas (ver subseção 6.3.3.1) para carregar os objetos do banco de dados.

public Vector obterVendas() { return bd.carregar(VendaProxy.class); }

100

Caso sejam requisitados os produtos de alguma instância de Vendas, a instância

Proxy fará o carregamento da instância real, como foi explicado no padrão Proxy

(subcapítulo 4.3). Segue a implementação do método obterProduto na classe

VendaProxy.

public Vector obterProdutos() { vendaReal = (VendaReal)bd.carregar(this.codigoContrato, VendaReal.class); return vendaReal.obterProdutos(); }

6.4.3 Camada de Persistência

A camada de persistência foi elaborada para que a aplicação ganhe em

estendibilidade e portabilidade. Assim foi criada uma classe Persistência, que servirá de

Fachada (ver sub capítulo 4.4, padrão Facade) para toda a camada de persistência, que

se constitui dos mapeadores das classes da camada de aplicação (ver subseção 6.3.3.3).

Para salvar um objeto, primeiramente a instância de Persistência define que

mapeador será usado. Isso é feito através do método retornarMapeador que recebe uma

classe como parâmetro e retorna uma instância da classe Mapeador. A classe que é

passada como argumento para o método retornarMapeador é a classe do parâmetro do

método salvar.

Para carregar um objeto, o sistema deve informar para a instância de Persistência

a classe do objeto que será carregado, e também um atributo identificador do objeto. A

implementação dos métodos salvar, carregar e retornarMapeador segue abaixo:

public void salvar(Object objeto) { Mapeador mapeador; mapeador = this.retornarMapeador(objeto.getClass()); mapeador.salvar(objeto); }

101

public Object carregar(int codigo, Class classe) { Mapeador mapeador; mapeador = this.retornarMapeador(classe); return mapeador.carregar(codigo); } public Mapeador retornarMapeador(Class classe) { Mapeador map; map = null; if (classe == Produto.class) { map = new MapeadorPeca(conn); } else { if (classe == VendaReal.class) { map = new MapeadorVendaReal(conn); } } . . . return map; }

6.4.4 Protótipo

Tendo uma parte da aplicação implementada, construiu-se uma simples interface

para demonstração do protótipo (figura 6.14). A interface limita-se a verificar o estoque,

realizar vendas, e obter as vendas feitas pelo sistema (utilizando o método obterVendas

para demonstração da aplicação do Proxy).

102

Figura 6.14 - Protótipo da Aplicação

6.4.4.1 Funcionamento do Protótipo

O protótipo inicia com um menu inicial de 3 opções. Estoque, Vender e

Consultar Vendas. Em Estoque pode-se conferir o estoque de produtos registrados, seu

código, seu preço e sua quantidade (figura 6.15).

Em Vender pode se efetuar uma venda de produtos. Na primeira coluna coloca-

se o código do produto, e ao lado, a sua quantidade. Clicando em Vender, a Venda é

efetuada. A quantidade dos produtos vendidos é deduzida dos produtos cadastrados no

estoque, e a venda é registrada no banco de dados (figura 6.16).

Em Consultar Vendas, as vendas realizadas são mostradas na tabela de vendas.

Selecionando uma venda na tabela e clicando no botão Detalhar Vendas, são mostrados

os produtos associados a respectiva venda na tabela inferior (figura 6.17).

103

Figura 6.15 – Consultando o estoque

Figura 6.16 – Realizando a venda

Figura 6.17 – Consultando a venda realizada

7 CONCLUSÃO

Através deste estudo, pode-se comprovar o grande potencial do uso dos padrões

no desenvolvimento de software. O domínio do problema escolhido para a construção

de uma aplicação, que demonstrasse os benefícios do uso de padrões, era relativamente

simples. Mesmo assim pode-se constatar ganhos em estendibilidade, desempenho,

reusabilidade e portabilidade.

7.1 Fatores de Qualidade Alcançados

7.1.1 Estendibilidade

Estendibilidade é a capacidade que a aplicação tem de se adaptar a novos

requisitos. Quanto menor for o esforço utilizado em uma alteração de requisitos, maior a

estendibilidade do sistema.

Pode-se comprovar a estendibilidade da aplicação de Controle de Atacado no

uso do padrão Contratos. A adição de uma nova atividade na empresa que envolva

contratos, exige apenas a adição de uma subclasse de Contratos, poupando trabalho

tanto do projetista como do programador.

Por exemplo, caso fosse adicionado o seguinte requisito: “o sistema deve

registrar o aluguel de produtos”, uma classe Aluguel, subclasse de Contrato, seria

adicionada ao projeto.

O uso do padrão de análise Conta, projetado usando-se o padrão Composite,

também aprimora a estendibilidade da aplicação, permitindo que se adicione um número

maior de componentes da classe Conta ao sistema. Pode-se facilmente implementar um

maior controle de contabilidade no sistema, adicionando, por exemplo, contas como:

despesa com material, despesa com funcionário, despesa com impostos, etc.

105

7.1.2 Desempenho

O desempenho de uma aplicação tem grande impacto na aceitação da aplicação

pelo usuário. Uma aplicação que não soluciona os problemas com velocidade perde um

pouco de sua aplicabilidade.

O ganho de desempenho é claramente demonstrado com o uso do padrão Proxy

na construção das subclasses de Contrato. No atacado usado como base para a

construção da aplicação, cada operação de consignação registra uma média de 80

produtos. O atacado tem cerca de 100 clientes que realizam 3 consignações por mês.

Assim uma consulta de todas as consignações do mês, sem a utilização do Proxy

resultaria no carregamento de 24000 objetos do banco de dados. Considerando que o

referido atacado é uma microempresa, o número pode crescer para valores inaceitáveis.

7.1.3 Reusabilidade

Todos os padrões utilizados na análise e no projeto são genéricos o bastante para

serem utilizados mais de uma vez. Reusabilidade é uma característica inata a um

software que foi analisado e projetado usando padrões.

7.1.4 Portabilidade

A aplicação desenvolvida tem um de seus pontos fortes na portabilidade, não só

por ser implementada numa linguagem multi-plataforma, mas o uso do padrão Facade

para implementação da camada de persistência torna toda a camada de aplicação

independente do sistema gerenciador de banco de dados.

A aplicação pode ser portada de um PC usando Windows como sistema

operacional e Oracle como banco de dados, para um computador usando Linux e

MySQL como banco de dados com pequenas alterações na classe Persistência.

106

7.2 Considerações Finais

Analisando os resultados, pode-se concluir que a utilização de padrões favorece

vários aspectos de qualidade de um software. Esta qualidade que possibilita as

constantes atualizações promovidas pelas grandes empresas de software, possibilita que

os erros de aplicações extremamente complexas sejam rapidamente detectados e

corrigidos e torna possível a portabilidade das aplicações num mundo onde a variedade

de sistemas e plataformas crescem a cada dia.

É imprescindível que softwares de médio e grande porte tenham sua análise e

seu projeto baseado em padrões, para tornar economicamente viável a uma

softwarehouse, operações como manutenção e atualização de seus programas.

Por outro lado, o uso dos padrões ainda sofre resistência por parte de analistas e

projetistas, principalmente iniciantes, pois a primeira vista, padrões se demonstram

confusos e sem utilidade. Iniciantes não conseguem visualizar os benefícios que um

esforço extra nas fases de análise e projeto irão trazer num futuro próximo.

Na grande maioria dos casos, a economia de trabalho que um padrão promove é

muito superior ao esforço extra que se faz na pesquisa e implementação do mesmo.

107

BIBLIOGRAFIA CONSULTADA

FOWLER, Martin. Analysis patterns: reusable object models. Addison-Wesley, 1997

GAMMA, Erich; HELM, Richard; JOHNSON, Ralph; et al. Design patterns: elements

of reusable object-oriented software. Reading, Massachusetts: Addison-Wesley, 1994.

LARMAN, Craig. Applying UML and patterns: an introduction to object-oriented

analysis and design and the Unified Process. 2. ed. Upper Saddle River, USA: Prentice

Hall PTR, 2001.

LARMAN, Craig. Utilizando UML e padrões: uma introdução à análise e ao projeto

orientados a objetos. Tradução de Luiz A. Meirelles Salgado, 1. ed. Porto Alegre:

Bookman, 2000.

KRUCHTEN, Philippe. The Rational Unified Process, an introduction. 2. ed.

Addison-Wesley, 2000.

MAFFEO, Bruno. Engenharia de Software e Especificação de Sistemas. Rio de

Janeiro: Campus, 1992.

SOMMERVILLE, Ian. Engenharia de Software. 6. ed. Addison-Wesley, 2003

SILBERSCHATZ, Abraham; KORTH, Henry. F; SUDARRSHAN, S. Sistema de

Banco de Dados. 3. ed. Makron Books, 1999.

108

IBPHOENIX. What is Firebird? Disponível em <http://www.ibphoenix.com>. Acesso

em: 4 de Janeiro de 2004.

SUN. Java 2 Platform, Standard Edition, v 1.4.2 API Specification. Disponível em

<http://java.sun.com/j2se/1.4.2/docs/api>. Acesso em: 20 de Dezembro de 2004.

109

ANEXOS

110

ANEXO I: Artigo

111

Aplicações de Padrões de Análise e Padrões de Projeto no Desenvolvimento de uma Aplicação de Controle de Atacado

Igor Ghisi

Ciências da Computação

INE – Departamento de Informática e Estatística Universidade Federal de Santa Catarina (UFSC), Brasil, 88040-900

[email protected]

O trabalho “Uso de Padrões de Análise e Padrões de Projeto no Desenvolvimento de uma Aplicação de Controle de Atacado” apresenta um conceito bastante novo no processo de desenvolvimento de software, o conceito de padrão.

Um padrão é uma solução para um determinado tipo de problema. A diferença desta solução está na forma de como ela é descrita. Sua descrição, mais geral e estruturada, favorece a sua utilização em problemas pertencentes a um mesmo contexto. Problemas cujo núcleo da solução seja semelhante.

Os padrões de análise descritos no trabalho são soluções de análise – um modelo conceitual orientado a objeto – para certos domínios de aplicação.

Já os padrões de projeto descrevem soluções de projeto e implementação para problemas de projeto de software. Os padrões descritos foram retirados do livro Design Patterns de Erich Gamma, considerado a Bíblia dos padrões de projeto de software.

No trabalho, foi sugerido um mapeamento de alguns padrões de análise para padrões de projeto, ou seja, formas de projeto e implementação para

os modelos conceituais descritos no padrão de análise. Assim, os domínios de aplicação cuja solução se encaixa em um dos padrões de análise mapeados, já terão uma solução definida para seu projeto.

Para comprovar a eficiência do uso dos padrões, foi desenvolvida uma aplicação usando-se um domínio comum. A aplicação era basicamente um sistema de controle de estoque e controle de caixa. Foi descrito todo o processo de desenvolvimento da aplicação. Nas partes do desenvolvimento onde foram utilizados padrões, foi explicado como e porque tais padrões eram utilizados.

Os benefícios e dificuldades do uso dos padrões foram demonstrados ao fim do trabalho, dando ênfase ao fator estendibilidade que os padrões agregaram a aplicação desenvolvida. O trabalho destaca que o tempo gasto no estudo e na aplicação dos padrões leva a um maior índice de reuso dos artefatos de desenvolvimento de software, inclusive o código de programação, concluindo como válida a aplicação de padrões para qualquer processo de desenvolvimento de software.

112

ANEXO II: Diagrama de Classes (Camada de Aplicação)

113

114

ANEXO III: Código da Aplicação

115

public class Atacado extends Entidade{ private Persistencia bd; /** Creates a new instance of Atacado */ public Atacado() { bd = Persistencia.obterPersistencia(); } public void vender(int codigoFun, int codigoCliente, int[] codigoProdutos, int[] quantidades, int nProdutos) { Vector vetorProdutos; vetorProdutos = bd.carregar(codigoProdutos, Produto.class, nProdutos); Vector vetorProdVendido = new Vector(); Vector vetorProdEstoque = new Vector(); for (int i = 0; i<vetorProdutos.size(); i++) { Produto produtoEstoque = (Produto)vetorProdutos.get(i); Produto produtoVendido = produtoEstoque.vender(quantidades[i]); vetorProdVendido.add(produtoVendido); vetorProdEstoque.add(produtoEstoque); } VendaReal venda = new VendaReal( 0, 0, vetorProdVendido); bd.salvar(venda); bd.salvar(vetorProdEstoque); //FAZER a Venda } protected void cadastrarProduto(int codigo, String descricao, double preco) { if (!(bd.existe(codigo, Produto.class))) { Produto novoProduto = new Produto(codigo, descricao, preco); bd.salvar(novoProduto); } }

116

public void comprarProduto(int codigo, int quantidade) { Produto prod = (Produto)bd.carregar(codigo, Produto.class); prod.quantidade = prod.quantidade + quantidade; bd.salvar(prod); } public VendaReal carregarVenda(int codigoVenda) { return (VendaReal)bd.carregar(codigoVenda, VendaReal.class); } public Vector obterEstoque() { return bd.carregar(Produto.class); } public Vector obterVendas() { return bd.carregar(VendaReal.class); } private Vector carregarProdutos(int[] codigoProdutos) { Vector vetorProduto = new Vector(); return bd.carregar(codigoProdutos, Produto.class, 1); } private void salvarProdutos(Vector vetorProdutos) { }

117

public interface Contrato { void gerarLancamento(double valor, String tipo, Date data_vencimento); //Lancamento[] fornecerLancamentos(); double calcularValorTotal(); Vector obterProdutos(); } public abstract class ContratoProxy implements Contrato { protected int codigoContrato; protected Date data; protected float valorTotal; /** Creates a new instance of ContratoProxy */ public ContratoProxy() { } public double calcularValorTotal() { return valorTotal; } public void gerarLancamento(double valor, String tipo, Date data_vencimento) { } protected void incrementarTotal(int valor) { } }

118

public class ContratoReal implements Cloneable, Contrato { /** * @clientCardinality 1 * @supplierCardinality 1..* * @label lancamentos*/ //private Lancamento lnkLancamento; protected int codigoContrato; protected Date dataInicio; protected Date dataFim; protected double valorTotal; protected Vector vetorProduto; /** Creates a new instance of Contrato */ public ContratoReal() { } /* public Lancamento[] fornecerLancamentos() { } */ public Vector obterProdutos() { return vetorProduto; } public double calcularValorTotal() { Iterator itProduto = vetorProduto.iterator(); while (itProduto.hasNext()) { Produto prod = (Produto)itProduto.next(); this.valorTotal = this.valorTotal + (prod.obterPreco() * prod.quantidade); } return valorTotal; } public void gerarLancamento(double valor, String tipo, Date data_vencimento) { } protected void incrementarTotal(int valor) { } public ContratoReal obterClone() { ContratoReal oClone = null; try { oClone = (ContratoReal)super.clone(); }

119

catch (Exception e) { System.out.println(e.getMessage()); } return oClone; } } public abstract class Entidade { protected String Nome; protected String Telefone1; protected String Telefone2; protected String email; /** Creates a new instance of Entidade */ public Entidade() { } public String obterNome() { return Nome; } } public interface Mapeador { Object carregar(int codigo); public Vector carregarTudo(); void salvar(Object objeto); void excluir(int codigo); boolean existe(int codigo); } public class MapeadorProduto implements Mapeador { public static Mapeador map = null; protected Connection conn; /** Creates a new instance of MapeadorProduto */ private MapeadorProduto(Connection _conn) { this.conn = _conn; try {

120

conn.setAutoCommit(false); } catch (Exception e) { System.out.println(e.getMessage()); } } public static Mapeador obterMapeador(Connection _conn) { if (map == null) { map = new MapeadorProduto(_conn); } return map; } public Object carregar(int codigo) { Produto prod; prod = new Produto(); try { Statement trans = conn.createStatement(); ResultSet result = trans.executeQuery(sqlSelectCodigo(codigo)); result.next(); prod.codigo = result.getInt("PR_CODIGO"); prod.preco = result.getDouble("PR_PRECO"); prod.descricao = result.getString("PR_DESCRICAO"); prod.quantidade = result.getInt("PR_QUANTIDADE"); } catch (Exception e) { System.out.println(e.getMessage()); } return prod; } public void excluir(int codigo) { int i =0; } public boolean existe(int codigo) { return false; } public void salvar(Object objeto) { Produto prod;

121

prod = (Produto)objeto; int codigo = prod.codigo; try { Statement trans = conn.createStatement(); ResultSet result = trans.executeQuery(sqlSelectCodigo(codigo)); if (result.next()) { trans.executeUpdate(this.sqlUpdate(codigo,prod.quantidade, prod.descricao , prod.preco)); } else { trans.executeUpdate(this.sqlInsere(codigo,prod.quantidade, prod.descricao , prod.preco)); } } catch (Exception e) { System.out.println(e.getMessage()); } try { conn.commit(); } catch (Exception e) { System.out.println(e.getMessage()); } } public Vector carregarTudo() { Vector vetorProduto = new Vector(); Produto prod; try { Statement trans = conn.createStatement(); ResultSet result = trans.executeQuery(sqlSelect()); while (result.next()) { prod = new Produto(); prod.codigo = result.getInt("PR_CODIGO"); prod.preco = result.getDouble("PR_PRECO"); prod.descricao = result.getString("PR_DESCRICAO"); prod.quantidade = result.getInt("PR_QUANTIDADE");

122

vetorProduto.add(prod.clonar()); } } catch (Exception e) { System.out.println(e.getMessage()); } return vetorProduto; } public class MapeadorVendaReal implements Mapeador { private static Mapeador map = null; protected Connection conn; /** Creates a new instance of MapeadorVenda */ private MapeadorVendaReal(Connection _conn) { this.conn = _conn; } public Object carregar(int codigo) { VendaReal venda; venda = new VendaReal(); try { Statement trans = conn.createStatement(); ResultSet result = trans.executeQuery("SELECT * FROM venda WHERE VE_CODIGO = " + String.valueOf(codigo)); result.next(); venda.codigoContrato = result.getInt("VE_CODIGO"); } catch (Exception e) { System.out.println(e.getMessage()); } venda.vetorProduto = this.carregarProdutos(venda.codigoContrato); return venda; } public Vector carregarTudo() { Vector vetorVenda = new Vector(); VendaReal venda; try { Statement trans = conn.createStatement();

123

ResultSet result = trans.executeQuery(sqlSelectAll()); while (result.next()) { venda = new VendaReal(); venda.codigoContrato = result.getInt("VE_CODIGO"); venda.valorTotal = result.getDouble("VE_VALOR"); vetorVenda.add(venda.obterClone()); } } catch (Exception e) { System.out.println(e.getMessage()); } return vetorVenda; } public void salvar(Object objeto) { VendaReal venda; venda = (VendaReal)objeto; int codigoVenda = this.carregeMaxCodigoVenda() + 1; int codigo = venda.codigoContrato; try { Statement trans = conn.createStatement(); ResultSet result = trans.executeQuery(sqlSelectCodigo(codigo)); if (result.next()) { //trans.executeQuery(this.sqlUpdate(codigo,venda.valorTotal)); } else { trans.executeUpdate(this.sqlInsere(codigoVenda, venda.valorTotal)); } } catch (Exception e) { System.out.println(e.getMessage()); } try { conn.commit(); } catch (Exception e) { System.out.println(e.getMessage()); } Vector produtos = venda.obterProdutos(); this.salvarProdutos(codigoVenda, produtos);

124

} public void excluir(int codigo) { } public boolean existe(int codigo) { return true; } public static Mapeador obterMapeador(Connection _conn) { if (map == null) { map = new MapeadorVendaReal(_conn); } return map; } private void salvarProdutos(int codigoVenda, Vector produtos) { try { Iterator itProdutos = produtos.iterator(); while (itProdutos.hasNext()) { Produto prod = (Produto)itProdutos.next(); Statement trans = conn.createStatement(); trans.executeUpdate(this.sqlInsereVendaProd(codigoVenda, prod.codigo, prod.quantidade)); conn.commit(); } } catch (Exception e) { System.out.println(e.getMessage()); } } private Vector carregarProdutos(int codigoVenda) { Vector vetorProdutos = new Vector(); Produto prod = null; Persistencia bd = Persistencia.obterPersistencia(); try { Statement trans = conn.createStatement();

125

vetorProdutos.add(prod.clonar());

ResultSet result = trans.executeQuery("SELECT PR_CODIGO, VE_PR_QUANT FROM venda_produto WHERE VE_CODIGO = "+ String.valueOf(codigoVenda)); while (result.next()) { int codigo = result.getInt("PR_CODIGO"); prod = (Produto)bd.carregar(codigo, Produto.class); prod.quantidade = result.getInt("VE_PR_QUANT");

} } catch (Exception e) { System.out.println(e.getMessage()); } return vetorProdutos; } private int carregeMaxCodigoVenda() { int max = 0; try { Statement trans = conn.createStatement(); ResultSet result = trans.executeQuery("SELECT max(VE_CODIGO) FROM venda"); result.next(); max = result.getInt(1); } catch (Exception e) { System.out.println(e.getMessage()); } return max; } public class Persistencia { private static Persistencia single; protected Connection conn; private Persistencia() { try { Class.forName("org.firebirdsql.jdbc.FBDriver");

126

DriverManager.registerDriver(new org.firebirdsql.jdbc.FBDriver()); } catch (Exception e) { System.out.println(e.getMessage());} try { String databaseURL = "jdbc:firebirdsql:localhost/3050:c:/projetos/sicefree/sicefree.GDB"; this.conn = DriverManager.getConnection(databaseURL, "sysdba", "masterkey"); } catch (Exception e) { System.out.println(e.getMessage()); } } public static Persistencia obterPersistencia() { if (single == null) { single = new Persistencia(); } return single; } public Object carregar(int codigo, Class classe) { Mapeador mapeador; mapeador = this.retornarMapeador(classe); return mapeador.carregar(codigo); } public Vector carregar(int[] codigos, Class classe, int nObjetos) { Vector vetor = new Vector(); int tam = Array.getLength(codigos); for (int i = 0; i<nObjetos; i++) { vetor.add(this.carregar(codigos[i],classe)); } return vetor; }

127

public Vector carregar(Class classe) { Mapeador mapeador; mapeador = this.retornarMapeador(classe); return mapeador.carregarTudo(); } public void salvar(Object objeto) { Mapeador mapeador; mapeador = this.retornarMapeador(objeto.getClass()); mapeador.salvar(objeto); } public void salvar(Vector vetorObjetos) { Mapeador mapeador; Object objeto = vetorObjetos.firstElement(); mapeador = this.retornarMapeador(objeto.getClass()); Iterator itObjetos = vetorObjetos.iterator(); while (itObjetos.hasNext()) { mapeador.salvar(itObjetos.next()); } } public void excluir(Object objeto) { } public boolean existe(int codigo, Class classe) { return false; } public Mapeador retornarMapeador(Class classe) { Mapeador map; map = null; if (classe == ConsignacaoReal.class) { map = new MapeadorConsignacaoReal(conn); }

128

if (classe == Produto.class) { map = MapeadorProduto.obterMapeador(conn); } if (classe == VendaReal.class) { map = MapeadorVendaReal.obterMapeador(conn); } return map; } }

129

public class Produto { protected double preco; protected int codigo; protected int quantidade; protected String descricao; public Produto() { } public Produto(int _codigo, String _desc, double _preco) { this.codigo = _codigo; this.descricao = _desc; this.preco = _preco; this.quantidade = 0; } public void consignar() { } public void devolver() { } public double obterPreco() { return this.preco; } public Produto vender(int qtd) { Produto prodVendido; prodVendido = this.clonar(); prodVendido.quantidade = qtd; this.quantidade = this.quantidade - qtd; return prodVendido; } public Produto clonar() { Produto clone = new Produto(); clone.codigo = this.codigo; clone.preco = this.preco; clone.descricao = this.descricao; clone.quantidade = this.quantidade; return clone;

130

} public interface Venda extends Contrato{ void Vender(int codigoFun,int codigoCliente,Vector Produtos); } public class VendaProxy extends ContratoProxy implements Venda { private VendaReal vendaReal; private Persistencia bd; public VendaProxy(int codigoFun, int codigoCliente, Vector Produtos) { bd = Persistencia.obterPersistencia(); } public void Vender(int codigoFun, int codigoCliente,Vector Produtos) { } public Vector obterProdutos() { vendaReal = (VendaReal)bd.carregar(this.codigoContrato, VendaReal.class); return vendaReal.obterProdutos(); } } public class VendaReal extends ContratoReal implements Venda { public VendaReal() {} public VendaReal(int codigoFun, int codigoCliente, Vector Produtos) { this.vetorProduto = Produtos; this.calcularValorTotal(); } public void Vender(int codigoFun, int codigoCliente, Vector Produtos) { } }