MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização...

76
1 UNIVERSIDADE FEDERAL DE SANTA CATARINA Departamento de Informática e Estatística Ciências da Computação MAGIC: Um framework para jogos de cartas por André Luís Knabben Thiago Robert Professor Doutor Ricardo Pereira e Silva Orientador Florianópolis, 06 de setembro de 2002.

Transcript of MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização...

Page 1: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

1

UNIVERSIDADE FEDERAL DE SANTA CATARINA Departamento de Informática e Estatística

Ciências da Computação

MAGIC: Um framework para jogos de cartas

por

André Luís Knabben Thiago Robert

Professor Doutor Ricardo Pereira e Silva Orientador

Florianópolis, 06 de setembro de 2002.

Page 2: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

2

UNIVERSIDADE FEDERAL DE SANTA CATARINA Departamento de Informática e Estatística

Ciências da Computação

MAGIC: Um framework para jogos de cartas

por

André Luís Knabben Thiago Robert

Professor Doutor Ricardo Pereira e Silva Orientador

Page 3: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

3

MAGIC: Um framework para jogos de cartas

Professor Doutor Ricardo Pereira e Silva Orientador

Professor Rosvelter Coelho Membro da Banca Avaliadora

Professor Vitório Mazzola Membro da Banca Avaliadora

Page 4: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

4

Resumo

Desenvolver aplicações utilizando o paradigma de orientação a objetos é uma tarefa

complexa. Entretanto, projetar artefatos de software visando a reusabilidade pode ser ainda

mais difícil. Frameworks e padrões de projeto estão entre os artefatos de software

reusáveis utilizados dentro do paradigma OO.

Um framework é um artefato de software reusável de alta granularidade que

generaliza um determinado domínio de aplicação, ou seja, cobre as características comuns

às aplicações de um domínio. É composto de classes abstratas e concretas e provê um

modelo de interação ou colaboração para as instâncias de suas classes.

Padrão de projeto é a descrição de uma solução para um problema de projeto que

ocorre constantemente. Padrões de projeto ajudam na escolha de alternativas para tornar

um sistema reusável, podendo até melhorar a documentação e manutenção de sistemas

existentes fornecendo uma especificação explicita da interação entre classes e objetos e o

objetivo dessa interação.

O presente documento consiste na descrição do desenvolvimento de um framework

OO generalizando o domínio dos jogos de carta. Padrões de projeto foram utilizados

durante o desenvolvimento do framework e, por isso, também são abordados.

Page 5: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

5

Abstract

Developing object oriented applications is a complex task. Designing reusable

software artifacts is even more complex. Frameworks and design patterns are among the

most popular reusable software artifacts in the OO paradigm.

A framework is a reusable software artifact that generalizes a given domain of

applications, i.e., it covers the common characteristics of every application in the domain.

A framework is composed of abstract and concrete classes and provides an interaction

model for the instances of its classes.

A design pattern describes the core of the solution to a problem which occurs over

and over again. Design patterns help in the selection of design alternatives that make a

system reusable and avoid alternatives that compromise reusability. Design patterns can

even improve the documentation and maintenance of existing systems by furnishing an

explicit specification of class and object interactions and their underlying intent.

The present paper consists in the description of the development of a card games OO

framework, using design patterns were used during the framework development and,

therefore, will be treated as well.

Page 6: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

6

Sumário

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

1.1 Tema ................................................................................................................................................... 10

1.2 Delimitação do Tema...................................................................................................................... 10

1.3 Objetivo Geral .................................................................................................................................. 10

1.4 Objetivos Específicos .................................................................................................................... 10

1.5 Motivação .......................................................................................................................................... 11

2. FRAMEWORKS ORIENTADOS A OBJETOS ............................................12

2.1 Conceitos Básicos.......................................................................................................................... 12

2.2 Vantagens ......................................................................................................................................... 13 Modularidade............................................................................................................................................... 13 Reusabilidade............................................................................................................................................... 13 Extensibilidade ............................................................................................................................................ 14

2.3 Desafios............................................................................................................................................. 14 Esforço de desenvolvimento ........................................................................................................................ 14 Curva de Aprendizado ................................................................................................................................. 15 Integração .................................................................................................................................................... 15 Manutenção.................................................................................................................................................. 15 Validação ..................................................................................................................................................... 15 Eficiência ..................................................................................................................................................... 15 Falta de Padrões ........................................................................................................................................... 15

2.4 Desenvolvimento de Frameworks .............................................................................................. 16 Análise do Domínio ..................................................................................................................................... 16 Modelagem .................................................................................................................................................. 16 Implementação............................................................................................................................................. 17 Testes ........................................................................................................................................................... 17 Documentação ............................................................................................................................................. 17

2.5 Metodologias de Desenvolvimento ............................................................................................ 18 Example-Driven Design .............................................................................................................................. 19 Hot Spot Driven Design............................................................................................................................... 19 Metodologia Taligent................................................................................................................................... 20

2.6 Ciclo de vida..................................................................................................................................... 20

3. PADRÕES DE PROJETO ...........................................................................22

4. FRAMEWORK PARA INTERFACE GRÁFICA ...........................................26

4.1 Análise do Domínio............................................................................................................................ 26

4.2 Projeto................................................................................................................................................. 27

4.3 Implementação ................................................................................................................................... 46

Page 7: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

7

4.4 Testes................................................................................................................................................... 47

4.5 Documentação .................................................................................................................................... 47

5. FRAMEWORK PARA JOGOS DE CARTAS ..............................................47

5.1 Análise do Domínio............................................................................................................................ 48

5.2 Projeto................................................................................................................................................. 49

5.3 Implementação ................................................................................................................................... 55

5.4 Testes................................................................................................................................................... 55

5.5 Documentação .................................................................................................................................... 58

6. CONCLUSÕES............................................................................................59

7. SUGESTÕES DE TRABALHOS FUTUROS ...............................................60

8. REFERÊNCIAS BIBLIOGRÁFICAS............................................................62

9. APÊNDICES ................................................................................................63

9.1 Guia para a criação de aplicações .................................................................................................... 63

10. ANEXOS......................................................................................................67

10.1 Código Fonte ...................................................................................................................................... 67

ARTIGO ................................................................................................................76

Page 8: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

8

Lista de Figuras

FIGURA 3. DIAGRAMA DE CLASSES DO PADRÃO DE PROJETO OBSERVER............................... 24 FIGURA 4. DIAGRAMA DE CLASSES DO PADRÃO DE PROJETO SECOND-GUESS. .................... 25 FIGURA 5. CASOS DE USO PARA O FRAMEWORK DE INTERFACE GRÁFICA............................ 27 FIGURA 6. RELACIONAMENTO ENTRE O MODELO E SUA VISÃO. .............................................. 28 FIGURA 7. INTERAÇÃO DINÂMICA ENTRE UM MODELO E A SUA VISÃO................................. 29 FIGURA 8. HIERARQUIA DE MODELOS PRESENTE NO FRAMEWORK DE INTERFACE

GRÁFICA................................................................................................................................................ 30 FIGURA 9. HIERARQUIA DE VISÕES PRESENTE NO FRAMEWORK DE INTERFACE GRÁFICA.

31 FIGURA 10. EXEMPLO DE RELACIONAMENTOS NA CRIAÇÃO DE VISÕES. ............................ 32 FIGURA 11. EXEMPLO DE INTERAÇÃO NA CRIAÇÃO DE VISÕES.............................................. 32 FIGURA 12. HIERARQUIA DE GERENTES DE DISPOSIÇÃO DE VISÕES. .................................... 33 FIGURA 13. SEQÜÊNCIA DE CHAMADAS PARA A GERÊNCIA DE DISPOSIÇÃO...................... 34 FIGURA 14. CLASSES QUE PARTICIPAM DO MECANISMO DE DESENHO. ............................... 35 FIGURA 15. SEQÜÊNCIA DE CHAMADAS PARA O MECANISMO DE DESENHO ...................... 37 FIGURA 16. HIERARQUIA DE EVENTOS ........................................................................................... 38 FIGURA 17. CLASSES QUE PARTICIPAM DO DISPARO DE EVENTOS. ....................................... 39 FIGURA 18. VISÃO DINÂMICA DO DISPARO DE UM EVENTO..................................................... 39 FIGURA 19. SUPORTE A VISUALIZAÇÃO DO OBJETO ARRASTADO.......................................... 41 FIGURA 20. CLASSES PARTICIPANTES DE UM DRAG AND DROP.............................................. 43 FIGURA 21. SEQÜÊNCIA DE CHAMADAS PARA UMA AÇÃO DE DRAG AND DROP. .............. 44 FIGURA 22. HIERARQUIA DE IMPLEMENTAÇÕES DE FRAMEIMPL............................................ 46 FIGURA 23. HIERARQUIA DE IMPLEMENTAÇÕES DE DRAWMANAGER. ................................... 46 FIGURA 24. APLICAÇÃO DESENVOLVIDA SOB O FRAMEWORK DE JOGOS DE CARTAS..... 48 FIGURA 25. CASOS DE USO PARA O FRAMEWORK DE JOGOS DE CARTAS............................. 49 FIGURA 26. HIERARQUIA DE MODELOS PRESENTE NO FRAMEWORK DE JOGOS DE

CARTAS. 50 FIGURA 27. HIERARQUIA DE CONDIÇÕES PARA ADIÇÃO DE CARTAS EM UM

PILEOFCARDS....................................................................................................................................... 51 FIGURA 28. HIERARQUIA DE CONDIÇÕES PARA REMOÇÃO DE CARTAS EM UM

PILEOFCARDS....................................................................................................................................... 52 FIGURA 29. ESTRUTURA DE CLASSES UTILIZADA PARA A DISTRIBUIÇÃO DE CARTAS. ... 53 FIGURA 30. MODELAGEM DINÂMICA DA DISTRIBUIÇÃO DE CARTAS.................................... 54 FIGURA 31. CLASSE BÁSICA DE UM JOGO DE CARTAS. .............................................................. 55 FIGURA 32. SCREENSHOT DO JOGO FREECELL. ............................................................................ 56 FIGURA 33. SCREENSHOT DO JOGO PACIÊNCIA............................................................................ 58

Page 9: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

9

Acrônimos e Abreviaturas

• API - Application Programming Interface (Interface para Programação de

Aplicativos)

• GUI - Graphical User Interface (Interface Gráfica com o Usuário)

• MVC - Model-View-Controller (paradigma para o desenvolvimento de interfaces

gráficas)

• OO - Orientação a Objeto

• OOAD - Object-Oriented Analisys and Design (Análise e Projeto Orientados a

Objetos)

• SDK - Software Development Kit (Kit de Desenvolvimento de Software)

• UFSC - Universidade Federal de Santa Catarina

Page 10: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

10

1. Introdução

Há décadas, a reusabilidade vem sendo uma das principais metas dos engenheiros de

software. Entretanto, reusar software não é nada simples e a maior parte dos esforços nesse

sentido acabou gerando apenas pequenos componentes caixa-preta. Com a popularização

do paradigma OO, tornou-se possível desenvolver componentes reusáveis de maior

granularidade, entre eles os frameworks OO. Atualmente existem frameworks para uma

grande variedade de domínios, entre eles podemos citar o MVC do Smalltalk e o AWT do

Java.

1.1 Tema

Desenvolvimento de frameworks com o uso de padrões de projeto.

1.2 Delimitação do Tema

O tema será trabalhado através do desenvolvimento de um framework específico

para jogos de carta.

1.3 Objetivo Geral

Explorar conceitos e técnicas de desenvolvimento de frameworks.

1.4 Objetivos Específicos

• Explorar as vantagens do uso de padrões de projeto no desenvolvimento de

aplicações.

• Criação de uma estrutura que facilite o desenvolvimento de aplicações no

domínio de jogos de cartas.

Page 11: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

11

• Criação de aplicações sob o framework desenvolvido.

1.5 Motivação

Vivemos hoje o paradoxo da indústria de software, isto é, a indústria de software

sente a necessidade de produzir programas altamente complexos no menor tempo e com o

menor custo possível. Um dos caminhos para a solução desse problema é o reuso: artefatos

de software reusáveis são produzidos e disponibilizados.

Frameworks são artefatos reusáveis de alta granularidade. A utilização de um

framework tem como objetivo a redução no tempo e no custo de criação e manutenção de

novas aplicações que pertençam ao domínio tratado por esse framework. Além disso, a

utilização desses artefatos de software resulta em aplicações mais confiáveis, pois, estando

o framework depurado, o desenvolvimento deixa pouca margem à inserção de erros.

Page 12: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

12

2. Frameworks Orientados a Objetos

"A framework is a set of classes that embodies an abstract design for solutions to a

family of related problems.1"

- Johnson-Foote 1988

Apesar de todos os avanços tecnológicos das últimas décadas, o projeto e a

implementação de aplicações complexas continuam caros e suscetíveis a erros. Grande

parte do custo e esforço de desenvolvimento dessas aplicações provém do constante

redescobrimento e reinvenção de conceitos e artefatos de software.

O framework OO é uma técnica de reuso de projeto e implementação com o objetivo

de reduzir o custo e melhorar a qualidade do software produzido.

2.1 Conceitos Básicos

Um framework é um conjunto de classes integradas que define uma estrutura

reusável para um domínio específico de aplicações. O framework provê uma arquitetura

particionada em classes abstratas e define as responsabilidades e um modelo de

colaboração para essas classes. O desenvolvedor adapta o framework para uma aplicação

particular especializando e agregando instâncias de suas classes. A figura abaixo ilustra

uma aplicação desenvolvida a partir de um framework. A estrutura em azul corresponde ao

framework e o restante é o que foi produzido pelo usuário do framework no

desenvolvimento dessa aplicação específica.

Figura 1. Uma aplicação desenvolvida sob um framework OO.

1 Um framework é um conjunto de classes que encorporam um projeto abstrato para a solução de uma família de problemas correlacionados.

Page 13: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

13

Frameworks portam a infra-estrutura de projeto, característica que reduz a

quantidade de código a ser desenvolvida na criação de aplicações. O modelo de

colaboração entre as classes de um framework define a arquitetura da aplicação livrando o

desenvolvedor dessa responsabilidade.

A arquitetura dinâmica de um framework é caracterizada por uma inversão de

controle. Essa arquitetura permite que o comportamento das aplicações seja alterado por

handlers2 invocados pelo framework. Quando determinado evento ocorre, o framework

reage invocando métodos em handlers pré-determinados, o que permite um processamento

de eventos específico para cada aplicação. A inversão de controle permite que o framework

(e não a aplicação) determine que métodos invocar em resposta a eventos externos

(princípio de Hollywood: "Don't call us, we'll call you3").

2.2 Vantagens

O uso de frameworks traz diversas vantagens para o desenvolvimento de aplicações:

Modularidade

Frameworks provêm modularidade, encapsulando implementações voláteis em

interfaces estáveis. A modularidade do framework ajuda a melhorar a qualidade do

software produzido, diminuindo o impacto de mudanças no projeto ou na implementação.

Além disso, com a modularidade reduz-se o esforço para entender e modificar aplicações

existentes.

Reusabilidade

As interfaces estáveis providas por um framework aumentam a reusabilidade

definindo estruturas genéricas que podem ser reutilizadas em diversas aplicações. O reuso

da estrutura de um framework gera grandes melhoras na produtividade e aumenta a

2 Manipuladores 3 “Não ligue para nós, nós ligaremos para você.”

Page 14: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

14

qualidade, performance, robustez e interoperabilidade das aplicações geradas.

Extensibilidade

Um framework melhora a extensibilidade através dos métodos hook4 e dos hot spots5

que permitem que uma aplicação aumente suas interfaces estáveis. A extensibilidade é

essencial para garantir a adaptação de características e comportamentos genéricos de um

domínio de aplicações a uma aplicação específica.

2.3 Desafios

Quando usado em conjunto com padrões, bibliotecas de classes e componentes, os

frameworks podem aumentar significativamente a qualidade da aplicação produzida e

reduzir o esforço de desenvolvimento. Entretanto, vários desafios devem ser vencidos

durante o desenvolvimento de um framework:

Esforço de desenvolvimento

O desenvolvimento de um framework genérico, extensível, reusável e de qualidade

para um domínio qualquer é um grande desafio e exige uma quantidade considerável de

esforço e tempo.

Desenvolver um framework para generalizar um domínio de aplicações muito

simples pode não compensar. Deve-se fazer uma análise detalhada da relação custo

benefício da criação de um framework antes de começar seu desenvolvimento.

O grande esforço desprendido no desenvolvimento de um framework é amenizado

pela rapidez com que aplicações de qualidade são desenvolvidas sob este framework.

4 Métodos hook formam, em conjunto com métodos template, um ponto de flexibilidade. Métodos hook podem ser redefinidos pela aplicação e são utilizados pelos métodos templates que implementam de forma genérica um algoritmo. 5 “Hot spots são as partes da estrutura de classes de um framework que devem ser mantidas flexíveis, para possibilitar sua adaptação a diferentes aplicações do domínio.” [SIL 98]

Page 15: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

15

Curva de Aprendizado

Assim como o esforço de desenvolvimento, o esforço necessário para aprender a usar

um framework OO é considerável. Entretanto, depois da fase de aprendizado é possível

começar o desenvolvimento de aplicações imediatamente.

Integração

O desenvolvimento de aplicações de grande porte pode ser baseado na integração de

diversos frameworks (um framework para a GUI e outro para a gerência de dados, por

exemplo). Essa integração nem sempre é fácil, pois a maioria dos frameworks são

desenvolvidos visando a extensibilidade interna e não a integração com outros frameworks.

Manutenção

A manutenção de frameworks é trabalhosa, pois é necessário um conhecimento

profundo da estrutura do framework e das relações entre suas classes.

Validação

Validar aplicações construídas a partir de frameworks é muito difícil. É praticamente

impossível distinguir os bugs do framework dos bugs da aplicação sendo desenvolvida.

Além disso, a inversão de controle do framework dificulta a depuração.

Eficiência

Frameworks aumentam a extensibilidade através de níveis adicionais de abstração.

Essa característica diminui ligeiramente a eficiência das aplicações desenvolvidas sob o

framework.

Frameworks não devem ser usados para a generalização de domínios onde o

principal requisito é a eficiência, como por exemplo, aplicações em tempo real.

Falta de Padrões

Page 16: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

16

Atualmente, não existe um padrão para o projeto, desenvolvimento, documentação e

uso de frameworks. Dentre as metodologias de desenvolvimento existentes, nenhuma pode

ser considerada um padrão. Essa característica prejudica o desenvolvimento, manutenção e

uso de frameworks.

2.4 Desenvolvimento de Frameworks

O desenvolvimento de um framework é ligeiramente diferente do desenvolvimento

de uma aplicação comum. A grande diferença é que um framework tem que cobrir os

conceitos relevantes a um domínio enquanto uma aplicação cobre apenas os conceitos

mencionados nos seus requisitos. O desenvolvimento de um framework pode ser dividido

da seguinte maneira:

Análise do Domínio

A análise de domínio é o processo de identificação e organização de conhecimentos a

respeito de uma classe de problemas – um domínio de aplicações – para suportar a

descrição e solução desses problemas. É um passo fundamental na criação de artefatos de

software reusáveis, pois elementos gerados através de uma análise de domínio capturam a

funcionalidade essencial requerida por um domínio.

Uma análise de domínio é um passo importante no desenvolvimento de frameworks,

pois faz com que o desenvolvedor do framework obtenha uma maior compreensão dos

conceitos do domínio, funcionalidades e hot spots que um framework deve possuir.

Modelagem

A modelagem de um framework consiste na especificação da estrutura de classes

desse framework. Essa estrutura de classes deve possuir algumas características

importantes:

• Generalidade – reflete a capacidade do framework de alterar suas

funcionalidades, tendo em vista as necessidades de uma aplicação específica.

Page 17: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

17

• Extensibilidade – refere-se à manutenibilidade do framework. O

desenvolvimento de frameworks é um processo iterativo, isto é, à medida que

o framework é utilizado novos recursos podem ser agregados a sua estrutura.

Assim, durante o projeto de um framework, deve-se tentar prever futuras

utilizações para este framework e futuras extensões no domínio tratado.

Implementação

A implementação de frameworks segue as linhas gerais da implementação de uma

aplicação comum. Todas as técnicas e padrões para o desenvolvimento de código podem

ser usados na implementação de um framework.

É importante ressaltar que o sucesso da implementação de um framework depende da

qualidade do projeto desse framework. Todas as características definidas durante a fase de

projeto devem ser mantidas na fase de implementação para que o framework não perca sua

capacidade de generalizar um domínio de aplicações.

Testes

Um framework é validado através da criação de aplicações teste, usadas para

determinar se o framework provê as funcionalidades desejadas e para avaliar sua

usabilidade.

Se, no processo de criação de aplicações, forem encontradas características do

domínio tratado que não estão presentes no framework deve-se reavaliar o projeto e

atualizar a implementação do framework para que essas características sejam adicionadas.

Essa retro-alimentação faz parte do ciclo de vida dos frameworks.

Documentação

O desenvolvimento e a utilização de frameworks são tarefas complexas e, por isso,

uma boa documentação é essencial. A documentação deve prover informações sobre o

domínio tratado pelo framework, sua estrutura e funcionamento.

Page 18: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

18

Frameworks podem ser descritos a partir de notações de metodologia OOAD como,

por exemplo, a UML. Essa descrição pode ser uma ótima fonte de informação sobre o

framework e, portanto, uma documentação valiosa.

Uma outra forma de documentação é a que ensina a usar o framework para gerar

aplicações. Esse tipo de documentação dá pouca ênfase a aspectos de projeto

concentrando-se na descrição do processo de criação de aplicações sob o framework. Um

exemplo desse tipo de documentação é o cookbook.

Cookbooks são conjuntos de receitas textuais para a utilização de um framework.

Sua principal vantagem é a capacidade de responder a questões chave minimizando o

tempo gasto para produzir aplicações. O principal problema dessa abordagem é que ela

cobre uma faixa limitada de tipos de aplicação. O auxilio proveniente do uso de um

cookbook pode ser ínfimo no caso das necessidades do usuário não se ajustarem ao

conjunto de problemas tratados pelo cookbook. [SIL 00]

Outro modo de documentar um framework, talvez o mais elementar, é a

disponibilização de código fonte aos usuários. O código fonte de um framework ou de

aplicações desenvolvidas sob esse framework é uma rica fonte de documentação.

Entretanto, é muito difícil entender o funcionamento de um framework apenas pelo seu

código fonte e, por isso, é recomendável que o código não seja a única fonte de referência

disponibilizada pelo autor do framework.

2.5 Metodologias de Desenvolvimento

Uma metodologia de desenvolvimento de frameworks consiste em procedimentos

que abrangem a captura das características de um domínio e a construção e teste da

estrutura de um framework. Essas metodologias se caracterizam por estabelecer o processo

de desenvolvimento de frameworks em linhas gerais, sem se ater à definição de técnicas de

modelagem ou detalhar o processo de desenvolvimento.

Existem poucas metodologias para o desenvolvimento de frameworks, dentre as

Page 19: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

19

quais podemos identificar três principais: example-driven design, hot spot driven design e a

metodologia Taligent.

Example-Driven Design

A metodologia “projeto dirigido por exemplos” (example-driven design) é

caracterizada pela análise de aplicações já desenvolvidas no domínio tratado, com o

objetivo de descobrir as características desse domínio. A abstração do domínio é obtida a

partir da generalização.

O processo de generalização ocorre a partir da busca de elementos semelhantes nas

diferentes aplicações de um domínio. Recorre-se a parametrização para eliminar as

diferenças. Elementos semelhantes de diferentes aplicações podem dar origem a classes

abstratas que agrupam as semelhanças.

Idealmente, no mínimo quatro aplicações existentes em um domínio deveriam ser

analisadas para que as semelhanças entre elas sejam identificadas. Entretanto, devido à

dificuldade de encontrar tantas aplicações já desenvolvidas num domínio especifico, pode-

se recorrer a um outro procedimento um pouco mais simples: o framework e um mínimo

de duas aplicações do domínio são desenvolvidos em paralelo. A troca de informações

durante o desenvolvimento em paralelo auxilia a busca de generalidade no framework.

Hot Spot Driven Design

A metodologia “projeto dirigido por pontos de flexibilização” (hot spot driven

design) enfatiza a busca de hot spots na estrutura de classes de um domínio. Hot spots são

as partes da estrutura de classes de um framework que devem ser mantidas flexíveis para

garantir que o framework cubra as diferentes aplicações do domínio tratado.

O desenvolvimento de frameworks auxiliado pela metodologia Hot Spot Driven

Design segue a seguinte seqüência de procedimentos:

• Identificação de classes – o desenvolvedor de frameworks, a partir das

informações obtidas na analise do domínio, define uma estrutura de classes

Page 20: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

20

inicial para o framework.

• Identificação de hot spots – é preciso identificar que aspectos diferem de

aplicação para aplicação e definir o grau de flexibilidade que deve ser

mantido em cada caso.

• Projeto do framework – modificação da estrutura de classes definida no inicio

do processo, de modo a comportar a flexibilidade requerida.

• Refinamento da estrutura do framework – refinamento da estrutura de classes

do framework a partir das informações obtida na analise do domínio. Nessa

etapa, se o framework não for flexível o suficiente para generalizar as

aplicações do domínio, deve-se voltar a etapa de definição dos hot spots.

Metodologia Taligent

A metodologia Taligent, proposta pela empresa de mesmo nome, difere das

anteriores pelo conjunto de princípios que norteiam o desenvolvimento de frameworks.

Primeiramente, a visão de desenvolver um framework que cubra as características e

necessidades de um domínio é substituída pela visão de produzir um conjunto de

frameworks estruturalmente menores e mais simples, que usados em conjunto, darão

origem às aplicações. Pequenos frameworks são mais flexíveis e podem ser reutilizados

mais freqüentemente. Assim, a ênfase passa a ser o desenvolvimento de frameworks

pequenos e direcionados a aspectos específicos do domínio.

Um outro aspecto é que uma das linhas mestras do desenvolvimento é tornar o uso

do framework o mais simples possível, através da minimização da quantidade de código

que o usuário deve produzir, através da disponibilidade de classes concretas que o usuário

pode usar diretamente, minimização do número de classes que devem ser criadas e

minimização do número de métodos que devem ser sobrepostos. [SIL 00]

2.6 Ciclo de vida

O ciclo de vida do desenvolvimento dos frameworks é diferente dos ciclos de vida

tradicionais para o desenvolvimento de aplicações comuns. Um framework não pode ser

considerado acabado. O desenvolvimento de aplicações sob frameworks invariavelmente

Page 21: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

21

vai revelar características do domínio que não foram tratadas. Cabe ao desenvolvedor

refinar o framework para que esse possa ser o mais abrangente possível.

Figura 2. O ciclo de vida do desenvolvimento de frameworks.

Análise do Domínio

Modelagem do Framework

Implementação do Framework

Refinamento do Framework

Aplicações sob o Framework

Page 22: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

22

3. Padrões de Projeto

"Each pattern describes a problem which occurs over and over again in our

environment, and then describes the core of the solution to that problem, in such a way that

you can use this solution a million times over, without ever doing it the same way twice.6”

- Christopher Alexander

Apesar do texto acima se referir a padrões usados por arquitetos para a descrição de

prédios e cidades, a mesma definição se aplica em sistemas orientados a objetos. Um

padrão de projeto nomeia e explica sistematicamente uma solução geral para um problema

recorrente em sistemas OO.

O padrão de projeto descreve o problema, a solução, quando aplicar a solução e as

conseqüências de sua aplicação. A solução é uma estrutura de classes e objetos que resolve

o problema. Uma definição mais específica para o âmbito de software OO seria:

“descriptions of communicating objects and classes that are customized to solve a general

design problem in a particular context7” [GAM 94].

Padrões de projeto capturam a essência de uma idéia que projetistas experientes

usaram diversas vezes para resolver um problema comum, abstraindo-se da situação

específica. Por isso, os padrões de projeto são independentes da aplicação e tem que ser

mapeados para uma situação específica antes de serem implementados.

De forma geral, um padrão de projeto possui os seguintes elementos [GAM 94]:

Nome do padrão

Encontrar um nome adequado é um dos passos mais importantes durante a descrição

de um novo padrão encontrado. O nome é utilizado como referência a um problema de

projeto, a sua solução e as suas conseqüências. Com ele é possível simplificar a

documentação, facilitar a comunicação entre membros de uma equipe de trabalho e 6 "Cada padrão descreve um problema que ocorre repetidamente em nosso meio, depois descreve o núcleo da solução para o problema de forma que se possa usar esta solução milhões de vezes, porém nunca da mesma forma."

Page 23: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

23

projetar num nível de abstração maior.

Descrição do Problema

Identifica qual o problema que o padrão visa solucionar e em que contexto ele pode

ser aplicado.

Solução

Descreve o padrão, isto é, os elementos que o constituem, seus relacionamentos e

responsabilidades. Como um padrão deve poder ser aplicado nas mais diferentes situações,

a descrição não pode ser baseada num exemplo concreto. Ao contrário, deve de forma

abstrata mostrar a organização geral da estrutura de classes e objetos que resolvem o

problema. Porém, pode ser incluído na descrição um exemplo de uma aplicação do padrão

a titulo de exemplo.

Conseqüências do uso

Indica as conseqüências da aplicação de um determinado padrão de projeto. Pode

incluir o impacto que o padrão traz em termos de flexibilidade, extensibilidade e

portabilidade, informações sobre trade-off de espaço e tempo e questões sobre

implementação em alguma linguagem de programação específica. Explicitar essas

considerações é importante, pois certas características de um padrão podem torná-lo

inapropriado a um contexto específico, como por exemplo, uma aplicação que demande

um tempo de resposta muito baixo. Além disso, se mais de uma solução estiver disponível,

essas informações podem ser usadas para a seleção da opção mais apropriada.

Existem padrões de projeto que são genéricos o suficiente para permitir a sua

aplicação nos mais diferentes domínios. No livro [GAM 94] foram catalogados vários

padrões genéricos. Porém cada domínio possui a sua própria coleção de padrões, que

podem ser também catalogados e descritos. Dois padrões de projeto estão expostos a seguir

exemplificando essas duas possibilidades. O primeiro padrão apresentado, de uso genérico, 7 "descrições de objetos e classes que se comunicam e que podem ser adaptados para resolver um problema

Page 24: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

24

é conhecido como Observer e foi retirado do livro [GAM 94]; o segundo, utilizado em

aplicativos de tempo real com controle contra falha, conhecido como Second-Guess foi

retirado de [DOU 99]:

Padrão Observer

Sub ject

attach(Observer)detach(Observer)notify()

Observer

update()

**

Concrete Observer

Concrete Subject

s tate

modifyState()getState()

+observers

+subject

Figura 3. Diagrama de classes do padrão de projeto Observer.

O padrão Observer permite remover a acoplamento entre um objeto que possui um

estado qualquer e outros objetos que dependam desse estado e que, portanto precisam ser

notificados quando ele mudar.

Esse padrão poderia ser aplicado, por exemplo, em um aplicativo que possui um

conjunto de dados qualquer e permite a visualização desses dados de mais de uma forma,

possivelmente simultâneas (tabela e gráfico de barras, por exemplo). Sempre que os dados

mudarem as suas representações devem ser avisadas e atualizadas.

geral de projeto num contexto específico"

Page 25: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

25

Padrão Second-Guess

Concrete Algorithm 1

Concrete Algorithm 2

Context

doSomething()

Algorithm

calculate()

#primaryCalculation

#secundaryCalculation

doSomething(){ prim aryCalculation.calculate() secundaryCalculation.calculate() if (results not s im ilar) take corrective action}

Figura 4. Diagrama de classes do padrão de projeto Second-Guess.

Esse padrão permite a utilização de duas implementações diferentes de um mesmo

algoritmo como forma de aumentar a confiabilidade do sistema. Ambos os algoritmos são

acionados e, caso haja uma diferença muito grande entre os resultados, uma condição de

erro foi detectada e alguma ação de correção pode ser executada.

Um exemplo de uso seria um sistema de controle de tráfego aéreo, onde o cálculo da

distância entre duas aeronaves é implementado de forma diferente por dois algoritmos.

Quando essa informação é requisitada, ambos são invocados. Caso algum algoritmo

apresente um valor errado (devido a um acúmulo de erros de arredondamento, por

exemplo), essa condição é detectada e um alarme pode ser acionado.

Page 26: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

26

4. Framework para Interface Gráfica

Durante o desenvolvimento do framework para jogos de carta, sentiu-se a

necessidade de criar uma estrutura de manipulação gráfica que desse suporte as seguintes

características:

• Independência de plataforma e linguagem

• Facilidade na implementação de estruturas gráficas estáticas

• Suporte a drag-and-drop para objetos gráficos complexos

Essa estrutura foi projetada visando extensibilidade, generalidade e simplicidade na

implementação dos aplicativos.

4.1 Análise do Domínio

Todos os sistemas operacionais que possuem interface gráfica disponibilizam uma

API para a criação de aplicativos gráficos. Geralmente, essa API consiste em um conjunto

de funções básicas para a construção de janelas, manipulação e controle de eventos, etc.

Normalmente, essa API é difícil de ser usada e, por isso, muitas vezes encontramos

uma camada intermediária embutida nas linguagens de programação que torna o

desenvolvimento mais simples e rápido. O mais famoso exemplo desse tipo de

intermediação é o VisualBasic da Microsoft.

Para obter uma melhor compreensão do domínio, estudou-se o suporte

disponibilizado por diversas linguagens. Por ser um sistema novo, orientado a objeto e com

código disponível, a principal fonte de referência foram os pacotes AWT/SWING do

Java® 1.4.

O diagrama abaixo lista os casos de uso com a visão de um usuário utilizando uma

aplicação desenvolvida sob o framework.

Page 27: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

27

Executar operações com o teclado

Arrastar componentes (drag)

Executar operações com o mouse

<<uses>>

Usuário da aplicação

Receber visualização gráfica

Figura 5. Casos de uso para o framework de interface gráfica.

O projeto desse framework, portanto, deve prover recursos que permitam ao

desenvolvedor da aplicação definir o comportamento de cada caso de uso acima descrito

de forma a implementar o seu aplicativo.

4.2 Projeto

Model-View-Controller

O Model corresponde a uma entidade ou abstração que vem diretamente do domínio

da aplicação ou da sua implementação. Este modelo não deve possuir informações externas

a ele, como, por exemplo, uma representação específica que será mostrada ao usuário.

Informações sobre o modo de exibição ficam numa classe separada (View). Mais de um

tipo de visualização é possível para cada modelo. Essa separação aumenta a reusabilidade

do modelo e permite a sua utilização nos mais diferentes contextos. Essa estrutura segue o

padrão de projeto Observer.

Page 28: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

28

Todas as entidades que podem ser manipuladas diretamente pelo usuário da

aplicação devem ser subclasses de Model. Para cada modelo criado onde se deseja uma

apresentação gráfica deverá ser criado um View específico.

A classe View representa um elemento qualquer que possua uma representação

gráfica e que possa receber estímulos do usuário. Sempre que o modelo mudar, sua

visualização deve ser também alterada, refletindo a mudança.

A cada View podem estar associados vários EventHandlers, responsáveis pelo

tratamento de eventos. A associação existente entre View e EventHandlers implementa o

padrão Strategy, permitindo a utilização de vários algoritmos de controle sem criar uma

associação forte entre a visualização e o controlador.

Para o usuário da aplicação desenvolvida, só a View importa, pois é por onde ele

receberá as informações e por onde ele interagirá com elas (através de dispositivos de

entrada como Mouse e teclado). Para o desenvolvedor da aplicação (usuário do

framework), apenas os Model importam, pois, conforme será explicado adiante, as Views

são automaticamente criadas pelo sistema.

Model

Model()addView(view : View) : voidnotifyViewers(changeInfo : Object) : voidremoveView(view : View) : void

EventHandler

handleCommonMouseEvent()handleDragEvent()handleKeyboardEvent()

View

View(model : Model)getModel() : Modelupdate(changeInfo : Object) : void

**#model

**

Figura 6. Relacionamento entre o modelo e sua visão.

Abaixo está descrito a dinâmica do processo de notificação entre Model e View

através de um exemplo real retirado do framework para jogos de cartas.

Page 29: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

29

Este exemplo parte da existência de uma carta (que é subclasse de Model) qualquer

no sistema. Para ela são criadas duas Views quaisquer8. Quando a carta é modificada, esta

avisa cada visão associada a ela, de forma que estas possam se atualizar.

Para melhorar a performance da atualização, junto com a notificação de que o Model

mudou também pode ser enviado um objeto que contém informações completas de qual

mudança ocorreu.

client aModel : FourSuitCard

view1 : FourSuitCardView

view2 : FourSuitCardView

setAttribute("Suit", FourSuitDeck.SPADES)notifyViewers(SUIT_CHANGED)

FourSuitCardView(aModel)

addView(view1)

FourSuitCardView(aModel)

addView(view2)

update(SUIT_CHANGED)

getAttribute("Suit")

update(SUIT_CHANGED)

getAttribute("Suit")

Figura 7. Interação dinâmica entre um modelo e a sua visão.

Hierarquia de Classes – Model

Os modelos dividem-se em AttributedModel e Attribute. Os Attributes são modelos

simples que representam atributos dos modelos mais complexos. O uso de um modelo

especial para representar atributos facilita a manipulação dos mesmos. 8 A criação de Views nesse exemplo é feita de forma manual, por simplicidade. Normalmente esse passo é feito automaticamente pelo framework.

Page 30: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

30

AttributedModels são os modelos complexos. Cada uma de suas características está

representada como um atributo. O usuário do framework pode estender essa classe para a

criação de modelos específicos, caso necessário. É sugerido que, quando o usuário for criar

um novo modelo9, essa classe sirva como base. Essa abordagem, porém, não é obrigatória.

O usuário pode criar novos modelos como subclasses de Model diretamente, caso desejado.

As classes PanelModel e ViewConfigurator possuem um papel fixo no framework e

serão explicadas a seguir.

AttributedModel

addAttribute()getAttribute()setAttribute()

IntegerAttrvalue : int = 0

PictureAttrfileName : String

StringAttrstring : String

Attribute

getType()change()isCompatible()

PanelModel

addModel()changeHandler()changeModel()getNumberOfModels()removeModel()

HOT SPOT

HOT SPOT

ViewConfiguration

CompositeModel

setViewFactory()addModel()removeModel()getNumberOfModels()getModel()

Model

Figura 8. Hierarquia de modelos presente no framework de interface gráfica.

Hierarquia de Classes – View

Cada Model que é mostrado ao usuário da aplicação deve possuir uma View

correspondente. Sempre que um usuário criar um novo Model ele deve também criar uma

View.

O diagrama abaixo mostra algumas visões disponíveis no framework.

9 O apêndice descreve como os hot spots definidos devem ser implementados.

Page 31: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

31

PanelView

PictureView HOT SPOT

ProxyView

Viewview

CompositeView

**

Figura 9. Hierarquia de visões presente no framework de interface gráfica.

Criação de visões

As visões são automaticamente criadas a partir de uma ViewFactory, que possui um

mapa dizendo qual View deve ser usada para cada Model.

Cada visão possui um objeto da classe ViewConfiguration que pode ser usado para a

sua configuração. Uma ViewFactory pode então armazenar a configuração que deve ser

usada quando for criar uma visão para um modelo qualquer. ViewFactory é um HotSpot

pois o usuário pode criar novas estratégias para a criação de Views. Isso porém demanda

um conhecimento muito maior a respeito do funcionamento interno do framework do que o

necessário para a criação de aplicações.

O ViewConfiguration representa os atributos da visão que podem ser configurados,

como por exemplo cor, transparência, etc. Cada View pode possuir os seus próprios

parâmetros de configuração. Uma visão para um bloco de texto pode ter a opção de definir

se o texto deve rolar automaticamente quando ele for maior do que o espaço disponível na

tela, por exemplo. A classe ViewConfigurator é subclasse de AttributedModel e pode

portanto possuir uma visão específica e um método uniforme de acesso e definição dos

seus atributos. Isso permite a criação de ferramentas gráficas que podem facilitar a

configuração de visões.

Page 32: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

32

DefaultViewFactory

DefaultViewFactory()createViewFor()

CompositeView

addView()ViewFactory

createViewFor()

#viewFactory

PanelView

modelChanged()

PanelModel

addModel()

#model

HOT SPOT

View

getViewConfiguration()

Figura 10. Exemplo de relacionamentos na criação de visões.

Abaixo a visão dinâmica da criação de uma visão para um Model qualquer.

client aPanel : PanelModel

viewForAPanel : PanelView

: ViewFactory

addModel(model)update()

getModel()

createViewFor(model)

addView(view)

Figura 11. Exemplo de interação na criação de visões.

Page 33: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

33

Gerentes de disposição

A classe PanelView, subclasse de CompositeView, usa um LayoutManager para

configurar o modo como suas visões estão dispostas na tela. Por exemplo, um PanelView

usando um PileLayout vai empilhar todas as suas visões. LayoutManager é um hot spot

pois é possível criar diferentes tipos de gerentes de disposição.

PanelViewLayoutManager

doLayout()

#panelView #layoutManager

PileLayout SpacedLayoutXYLayout HOT SPOT

Figura 12. Hierarquia de gerentes de disposição de visões.

A seguir o funcionamento básico de uma operação de gerenciamento de disposição.

Quando algum atributo do PanelView é alterado (um novo elemento foi adicionado, por

exemplo), este chama fixLayout(), que reorganiza as visões dentro do painel.

Page 34: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

34

: PanelView : LayoutManager

: View

fixLayout( )doLayout( )

getNumberOfViews( )

getView()

setBounds()

getBounds( )

Para cada View, calcule posição e defina.

Figura 13. Seqüência de chamadas para a gerência de disposição

Mecanismo de desenho

O diagrama de classes abaixo ilustra o relacionamento entre as classes envolvidas no

desenho da interface gráfica.

• Surface é uma superclasse abstrata que pode ser passada ao DrawScheduler,

que chama um método quando esta superfície precisar ser desenhada.

• DrawScheduler é responsável por diminuir a freqüência com que uma

superfície sofre uma operação de desenho. Mudanças seqüenciais num curto

espaço de tempo são agregadas em uma única operação de desenho,

melhorando a performance do sistema.

• Um Frame é uma janela gráfica que possui a superfície de desenho que será

mostrada ao usuário. Como a implementação dessa classe é dependente de

plataforma, a classe FrameImpl encapsula a parte específica.

• O Frame possui um ImageBuffer, que é uma área de memória onde uma

figura pode ser armazenada. Essa figura é usada para armazenar a imagem

gerada numa operação de desenho. Quando alguma View muda, só a área

afetada pela mudança precisa ser redesenhada.

Page 35: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

35

FrameImpl

endScreenUpdate() : voidstartScreenUpdate() : DrawManager

FrameImageBuffer

createDrawManager() : DrawManager

#doubleBuffer

DrawSchedulerSLEEP_AMOUNT : int = 10

schedule()

Surface

drawNow()

**

Figura 14. Classes que participam do mecanismo de desenho.

As funções utilizadas para o desenho de uma visão

ficam agregadas numa classe abstrata chamada

DrawManager. Toda operação de desenho é efetuada

através da chamada das funções definidas por essa classe.

Como cada superfície de desenho pode possuir

métodos distintos para implementar cada operação de

desenho (desenhar em uma área de memória é muito

diferente de desenhar em uma janela de interface), essa

classe possui muitas implementações possíveis. Para cada

superfície de desenho uma implementação específica deve ser gerada. A superfície de

desenho deve então prover um método (padrão de projeto Factory Method) para a criação

de um objeto DrawManager compatível.

A view mantém uma lista de áreas danificadas, isto é, áreas

onde alguma mudança ocorreu e que portanto deve ser

redesenhada. Essas áreas são redesenhadas quando o método

drawDamagedAreas() é invocado. O framework é responsável

por invocar esse método, de forma a seguir a hierarquia de visões

dentro de uma janela. Dessa forma uma View que está sobre outra

só será desenhada após essa última.

A função drawDamagedAreas() é redefinida no CompositeView de forma a repassar

o comando de desenho a todas as views que se encontram sobre a área afetada.

A seguir um exemplo da interação entre objetos num evento de atualização da

DrawManager

clearArea()drawImage()drawString()setColor()

JavaDrawManager

JavaOffscreenDrawManager

CompositeView

View

addDamagedArea()drawDamagedAreas()isDamaged()

Page 36: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

36

interface. O exemplo supõe que sobre um Frame existe um View que deve ser atualizada

pois o seu Model mudou.

A View afetada então invalida a sua área (marcando como danificada) e chama o

DrawScheduler para agendar uma atualização da superfície onde esta View se encontra.

Quando o DrawScheduler decide que a superfície deve ser atualizada, este chama o

método drawNow() do Frame, que manda a View se redesenhar no seu buffer. Por último o

Frame envia a área redesenhada para o FrameImpl, que mostra o novo estado para o

usuário.

Page 37: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

37

: Model : View : DrawScheduler

frame : Frame doubleBuffer : DrawManager

frameImpl : FrameImpl

update()modelChanged()

invalidate( )

addDamagedArea()

schedule(surface)

drawNow( )

Essa chamada ocorre em thread separada, de forma assincrona.

drawDamagedAreas(bufferManager)

drawArea(damagedArea, bufferManager)

createDrawManager(view.bounds)

drawDamagedAreas(clippedDrawManager)

drawArea()

startScreenUpdate( )

endScreenUpdate( )

updateScreen( )

Figura 15. Seqüência de chamadas para o mecanismo de desenho

Controle de Eventos

Para permitir que o usuário interaja com o aplicativo desenvolvido, o desenvolvedor

de aplicações define EventHandlers, que são classes responsáveis por tratar os eventos

feitos pelo usuário.

Quando um usuário clica numa visão qualquer, um evento do mouse é gerado pelo

framework e enviado para o EventHandler associado à visão clicada. Esse handler pode

executar qualquer tipo de ação em resposta ao evento. Por exemplo, se a visão for um

botão, a resposta ao evento pode ser a impressão de um documento.

Vários tipos de eventos são definidos pelo framework, sendo que cada um possui

Page 38: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

38

uma implementação específica e um conjunto de atributos associados.

Eventos básicos do mouse (clique, movimentação, etc...) são definidos pela classe

CommonMouseEvent e possui informações como qual botão foi pressionado e qual a

posição em que a ação ocorreu. A posição do evento é sempre relativa à posição superior

esquerda da visão que recebeu o evento. Manter o botão do mouse pressionado em cima de

uma View faz com que a visão sob o mouse passe a ser receptora de todos os eventos

gerados por esse até que o botão seja solto. Essa característica foi observada em todas as

aplicações do domínio estudado e foi portanto replicada.

O Frame possui também a capacidade de identificar o início de uma operação de

drag and drop. O evento DragEvent é enviado quando isso acontece.

Eventos do teclado são enviados através do evento KeyboardEvent e são enviados

para a View que possui o foco no momento do pressionamento da tecla.

DragEventDRAG_ENDEDDRAG_START...

acceptDrop() : booleanwasDragAccepted() : booleanwasDropAccepted() : boolean

MouseEvent

getButton()getX()getY()

CommonMouseEventMOUSE_CLICKMOUSE_MOVE...

getAction()

KeyboardEvent

getButton()getModifiers()

EventHandler

handleCommonMouseEvent()handleDragEvent()handleKeyboardEvent()

Event

callHandler()

Figura 16. Hierarquia de eventos

Page 39: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

39

As classes EventHandler e Event se comportam seguindo o padrão de projeto Visitor

de forma a facilitar a chamada do método correto no handler para o evento disparado.

FrameImpl

EventHandler

handleCommonMouseEvent()handleDragEvent()handleKeyboardEvent()

Frame

handleKeyboardEvent()handleMouseEvent()

View

handleKeyboardEvent()handleMouseEvent()

****

Figura 17. Classes que participam do disparo de eventos.

O diagrama de colaboração abaixo mostra a seqüência de ações para o disparo de um

evento do mouse.

: JavaFrameImpl

: Framejava virtual machine

targetContainer : CompositeView

realTarget : View

targetHandler : EventHandler

2: createMouseEvent(javaMouseEvent)4: findTarget(event.coords)

5: convertToChildCoords(event)

7: findTarget()8: convertToChildCoords()

event : CommonMouseEvent

3: handleMouseEvent(event)

6: handleMouseEvent(event)

1: dispatch event(javaMouseEvent)

11: handleCommonMouseEvent()

9: handleMouseEvent(event)

10: callHandler(realTarget, targetHandler)

Figura 18. Visão dinâmica do disparo de um evento.

Page 40: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

40

Suporte a Drag and Drop

Criar um suporte genérico a drag and drop foi um dos maiores desafios na construção

do framework para interface gráfica.

Os requisitos definidos foram os seguintes:

• Qualquer Model que possuísse uma visão poderia ser arrastado. Isso exige

um mecanismo eficiente para desenho da visão associada, pois o objeto

arrastado pode ser bastante complexo (como um painel com vários

componentes internos).

• A superfície onde o objeto está sendo arrastado pode mudar, devendo ser

normalmente atualizada.

• Durante o arrasto, se o objeto mudar essa mudança deve ser refletida na

interface. Dessa forma a figura sendo arrastada não é necessariamente

estática.

Eficiência nesse caso é extremamente importante pois durante o drag and drop a

View sendo arrastada deverá ser redesenhada várias vezes por segundo, de forma a garantir

precisão e conforto visual ao usuário da aplicação. De forma a garantir isto, um mecanismo

específico foi adicionado à classe Frame. A visão sendo arrastada é desenhada num buffer

extra e fixo, que é atualizado apenas quando a visão muda. Como o Frame já possui um

buffer com toda a visão da aplicação já desenhada, os seguintes passos são necessários a

cada movimento do mouse. Esses passos são efetuados diretamente na janela do aplicativo

(classe FrameImpl):

1. Cópia do buffer do Frame na área ocupada anteriormente pela View.

2. Cópia do buffer da View na nova área a ser ocupada.

Dessa forma fica garantida a eficiência necessária ao processo.

O diagrama abaixo contém as classes envolvidas no processo de redesenho durante

uma operação de drag and drop.

Page 41: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

41

• Frame é responsável por detectar um movimento de drag (mover o mouse

com o botão pressionado) e pela gerência geral da operação, como redesenhar

o objeto quando o mouse se mover e terminar o movimento quando o botão

for liberado.

• DragManager contém informações sobre a operação de drag and drop, tais

como quem foi o iniciador da operação e qual o objeto que está sendo

arrastado.

• DragPanel contém um buffer que armazena a imagem do modelo arrastado e

é responsável por atualizar essa imagem sempre que o modelo mudar. Essa

classe também é responsável por criar uma visão para o modelo.

Surface

drawNow()

Frame

DragManager

endDrag()isDragging()startDrag()

DragPanel

drawDragImage()setDragModel()

View

#viewBeingDragged

Figura 19. Suporte a visualização do objeto arrastado

Page 42: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

42

De forma a implementar drag and drop em uma aplicação, o desenvolvedor deve

criar uma ou mais subclasses de DragEventHandler e associá-las a View que irá receber o

início do drag e a todas as Views que podem ser alvo para um drop. Cada ação possível

possui um código específico no DragEvent e deve ser tratado de forma diferente.

Os passos para a definição de um DragEventHandler são os seguintes:

1. Criar uma subclasse de DragEventHandler.

2. Implementar o método dragStart(), que deverá chamar acceptDrag() do

DragEvent() passado por parâmetro. Nessa chamada deve ser definido qual

modelo será usado para a visualização do drag e opcionalmente pode ser

passado um objeto qualquer contendo alguma informação associada ao drag.

Essa informação estará acessível para a View que receber o drop. Deve ser

observado que o protocolo de drag and drop não retira nenhuma View do

sistema, dessa forma, se o objetivo for que a View fonte do drag and drop seja

removida, isso deve ser implementado nesse método.

3. Implementar o método dragDrop(), que deverá chamar acceptdrop() no

evento caso o drop seja aceito. Esse método pode chamar getInfo() para obter

qualquer informação passada durante o drag().

4. Implementar o método dragEnd(). Esse método é chamado na View que

originou o evento, informando se o drop foi aceito ou não. Isso pode ser

usado caso o drag and drop esteja sendo usado para mover um objeto de um

lugar para outro. Se o objeto não foi depositado numa região válida, então ele

deve retornar à posição anterior, por exemplo.

5. Implementar o método dragOver(). Esse passo é opcional e permite, por

exemplo, que algum indicativo (como mudar de cor) de que o drop é aceito

pela View sob o mouse possa ser implementado.

Page 43: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

43

Abaixo as classes utilizadas para a implementação de drag and drop.

DragEventHandler

dragDrop()dragEnd()dragOver()dragStart()handleDragEvent()

DragEventDRAG_DROP : int = 3DRAG_END : int = 4DRAG_OVER : int = 2DRAG_START : int = 1

acceptDrag(modelToDrag : Model, info : Object) : voidacceptDrop() : voidgetInfo() : ObjectwasDragAccepted() : booleanwasDropAccepted() : boolean

Figura 20. Classes participantes de um drag and drop.

O diagrama de seqüência abaixo mostra os passos efetuados pelo framework no

decorrer de um evento de drag and drop.

Page 44: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

44

Figura 21. Seqüência de chamadas para uma ação de drag and drop.

: Fr

ame

sour

ceV

iew

: V

iew

: D

ragE

vent

Han

dler

drag

Sta

rt :

Dra

gEve

ntdr

agD

rop

: D

ragE

vent

: D

ragM

anag

er :

Dra

gPan

eldr

opV

iew

: V

iew

hand

leM

ouse

Eve

nt(d

ragS

tart)

hand

leD

ragE

vent

()dr

agS

tart(

)

acce

ptD

rag(

mod

elTo

Dra

g)

was

Dra

gAcc

epte

d( )

star

tDra

g(m

odel

ToD

rag)

setD

ragM

odel

()

Um

a V

iew

é

cria

da.

draw

Now

( )ha

ndle

Mou

seE

vent

(mou

seM

ove)

draw

Dra

gIm

age(

)

hand

leM

ouse

Eve

nt(m

ouse

Up)

hand

leM

ouse

Eve

nt(d

ropE

vent

)ha

ndle

Dra

gEve

nt()

drag

Dro

p()

was

Dro

pAcc

epte

d( )

hand

leM

ouse

Eve

nt()

hand

leD

ragE

vent

()dr

agE

nded

()

endD

rag(

)

draw

Dra

gIm

age(

)

Page 45: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

45

Suporte a diferentes linguagens e sistemas operacionais

Conforme citado, um dos requisitos propostos foi que o framework desenvolvido

fosse facilmente portado para diferentes plataformas e linguagens. Para garantir isso as

partes que possuem relacionamento direto com o sistema operacional ou com a linguagem

foram isoladas em classes específicas e substituíveis.

Essa classe implementa o padrão de projeto Abstract

Factory. Classes que possuam uma implementação dependente de

plataforma devem incluir um método na ResourceFactory que

será usado para criar um objeto compatível com o sistema utilizado. Dessa forma quando o

framework for portado ou quando uma aplicação estiver executando em um sistema

diferente do original nada precisa ser atualizado.

ImageBuffer representa uma área em

memória que pode ser usada para armazenar

imagens ou gráficos de qualquer tipo. Como cada

sistema possui métodos específicos para a criação

desses objetos, a implementação desse objeto é

específica para a plataforma sendo utilizada.

FrameImpl e DrawManager também

possuem implementações específicas para cada plataforma.

JavaImageBuffer

ImageBuffer

createDrawManager()

WindowsImageBuffer

X11ImageBuffer

ResourceFactory

createFrameImpl()createImageBuffer()

Page 46: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

46

Frame

centerInScreen()drawNow()getScreenSize()

FrameImpl

endScreenUpdate()getScreenSize()startScreenUpdate()

WindowsSurfaceImplJavaFrameImpl

Figura 22. Hierarquia de implementações de FrameImpl.

DrawManager

drawImage()drawString()

JavaDrawManager

JavaOffscreenDrawManager

X11DrawManager

Figura 23. Hierarquia de implementações de DrawManager.

4.3 Implementação

Durante a implementação usou-se o ambiente de desenvolvimento Jbuilder 7

Enterprise Edition juntamente com o SDK Java 1.4. O código está disponível no CD em

anexo ou no site http://www.inf.ufsc.br/~ricardo/magic/.

Page 47: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

47

4.4 Testes

O framework para interface gráfica foi usado durante o desenvolvimento do

framework para jogos de cartas e, portanto, as aplicações desenvolvidas sob o segundo

framework serviram para validar o primeiro. A seção 5.4 descreve em detalhes as

aplicações desenvolvidas sob o framework para jogos de carta.

4.5 Documentação

Os diagramas UML apresentados neste capítulo fazem parte da documentação

desenvolvida para o framework descrito. Esses diagramas foram simplificados para

facilitar a leitura e entendimento do documento. A versão completa dos diagramas está

disponível no CD em anexo ou no site http://www.inf.ufsc.br/~ricardo/magic/.

O código fonte é outra forma de documentação. Esse código está comentado com

JavaDocs e o HTML automaticamente gerado está disponível em

http://www.inf.ufsc.br/~ricardo/magic/. Detalhes sobre o código estão descritos na seção

4.3.

5. Framework para Jogos de Cartas

O domínio dos jogos de cartas pode parecer simples à primeira vista, entretanto, é

um domínio vasto e sua análise e generalização exige muita atenção com os detalhes sutis

que poderiam passar despercebidos. A generalização desse domínio em um framework tem

o objetivo didático de fixar os aspectos referentes ao desenvolvimento e utilização de

frameworks.

O framework de jogos de cartas foi criado sob o framework de interface gráfica,

como demonstra a figura abaixo:

Page 48: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

48

Figura 24. Aplicação desenvolvida sob o framework de jogos de cartas.

5.1 Análise do Domínio

Analisando várias aplicações10 no domínio de jogos de cartas pode-se chegar a três

entidades básicas:

• Carta – comum a todos as aplicações desse domínio, essa é a entidade básica

de qualquer jogo de cartas.

• Baralho – todas as cartas de um jogo fazem parte de um baralho.

• Conjunto de cartas – a ação mais comum de um jogador num jogo de cartas é

mover uma carta de um conjunto de cartas para outro.

A quantidade de entidades desses tipos, a interação entre essas entidades e a

interação do usuário com essas entidades varia dependendo do jogo.

O diagrama abaixo contém os casos de uso para uma aplicação desenvolvida sob o

framework.

10 Dentre as aplicações estudadas podemos citar: paciência, truco, poker e blackjack.

Page 49: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

49

Iniciar jogo

configurar jogo

Jogar

Encerrar jogo

Jogador

Figura 25. Casos de uso para o framework de jogos de cartas.

5.2 Projeto

Procurou-se modelar o framework tendo em vista a generalidade, extensibilidade e

interoperabilidade. O projeto é genérico e pode ser usado como base para o

desenvolvimento de frameworks para jogos de cartas em qualquer linguagem e para

qualquer plataforma.

Hierarquia de Classes – Card

Cartas são o elemento básico de todos os jogos de cartas. Cada jogo possui diferentes

tipos de carta e por isso a classe Card é um hot spot. FourSuitCard é uma implementação

concreta de Card e refere-se à carta comum (com um número e um naipe) usada na maioria

dos jogos. SetOfCards é simplesmente um conjunto de cartas. PileOfCards representa uma

Page 50: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

50

das diferentes pilhas encontradas nos jogos, como por exemplo a mão de um jogador ou a

pilha de compra.

FourSuitCard PileOfCards

setAddCondition()setRemoveCondition()

AttributedModel

Model

HOT SPOT

SetOfCardCard **

Figura 26. Hierarquia de modelos presente no framework de jogos de cartas.

PileOfCards

PileOfCards implementa um monte

qualquer dentro de um jogo de cartas. Esse

monte pode ter vários layouts diferentes,

como uma carta sobre a outra, uma ao lado da

outra ou em cascata vertical.

É essa classe que contém as regras do

jogo, dizendo qual carta pode ser movida para

qual lugar através de condições de entrada e

saída de cartas. Essas condições são

implementadas através das classes descritas a

PileOfCardschainRemoval : booleandefaultCardOrientation : booleanLAYOUT_TYPE_HORIZONTAL : int = 2LAYOUT_TYPE_PILE : int = 0LAYOUT_TYPE_VERTICAL : int = 1

addCardTestingCondition()enableConditions()isChainRemovalOn()isDragEnabled()removeAndSaveTestingCondition()removeCardTestingCondition()restoreSavedCard()setAddCondition()setDrag()setRemoveCondition()

Page 51: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

51

seguir e seus métodos são invocados sempre que o usuário tenta remover uma carta de

algum PileOfCards e quando ele tenta adicioná-la em outro. Essa classe define também se

a remoção de uma carta do meio do baralho (utilizado em geral com o layout cascata) deve

efetuar a remoção de todas as cartas a partir dessa (para mover uma coluna no jogo

Paciência, por exemplo). Além disso, o método removeAndSaveTestingCondition()

permite a remoção de uma carta ou de um conjunto de cartas mantendo uma referência à

lista removida. Dessa forma as visões são atualizadas, excluindo as cartas removidas, mas

um simples método (restoreSavedCard()) faz com que as cartas sejam adicionadas

novamente no monte na posição em que estavam antes da remoção. Isso facilita, por

exemplo, a implementação de drag and drop, pois permite anular o drag caso o destino não

aceite as cartas sendo movidas.

As condições para entrada e saída de cartas implementam o padrão de projeto

Strategy, permitindo que um algoritmo seja trocado a qualquer hora, porém sem colocar a

implementação de cada tipo de algoritmo dentro da classe que usa ele.

As classes AddCardCondition e RemoveCardCondition possuem métodos que devem

retornar verdadeiro se a alteração (inclusão ou remoção de carta) for aceita e falso caso

contrário. Os parâmetros passados para essas funções contêm informações que possibilitam

a implementação de uma grande quantidade de algoritmos, sendo que a maioria deles

utilizará apenas um subconjunto dos dados fornecidos. Os parâmetros fornecidos diferem

entre AddCardCondition e RemoveCardCondition.

SpecificSuitAddCondition InOrderAddCondition

AddCardCondition

testAdd()testAdd()

CompositeAddCondition

**

HOT SPOT

Figura 27. Hierarquia de condições para adição de cartas em um PileOfCards.

Page 52: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

52

HOT SPOT

OnlyLastCardsRemoveCondition TrueRemoveCondition CompositeRemoveCondition

RemoveCardCondition

testRemove()testRemove()

*

Figura 28. Hierarquia de condições para remoção de cartas em um PileOfCards.

Distribuição de Cartas

O diagrama de classes abaixo ilustra o relacionamento entre as classes envolvidas na

distribuição de cartas.

• Um Deck é composto de várias cartas e é a fonte de cartas do distribuidor

• FourSuitDeck é o baralho com 52 cartas de quatro tipos (naipes) diferentes,

usado na maioria dos jogos

• StandardCardDistribuitor é uma implementação concreta de CardDistribuitor

que pega as cartas de um baralho e as divide entre vários SetOfCards (mão

dos jogadores, pilha de compra, etc.)

• CompositeDeck e CompositeCardDistribuitor implementam o padrão de

projeto Composite.

• Deck e CardDistribuitor são hot spots pois o usuário do framework pode

querer criar novos tipos de baralhos e distribuidores com um comportamento

diferente dos existentes.

Page 53: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

53

CompositeCardDistributor

addDistributor()removeDistributor()

CardDistributor

distribute()

**

FourSuitDeck

CompositeDeck

addDeck()getNumberOfDecks()removeDeck()

Deck

Deck()initialize()fillDeck()getRandomCard()getNumberOfCards()getCards()

**

StandardCardDistributor

addDestination()addSplitDestination()setSource()

#source

Card**

SetOfCard*

#destinations

*

**

HOT SPOT

HOT SPOT

SpadesSuitDeck

HOT SPOT

Figura 29. Estrutura de classes utilizada para a distribuição de cartas.

Dinamicamente, o processo de distribuição de cartas se comporta da seguinte

maneira:

Page 54: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

54

Client : StandardCardDistributor

fiveCardDeck : Deck

hand1 : CompositeCard

hand2 : CompositeCard

remaining : CompositeCard

setSource(aDeck)

addDestination(hand1, 2)

addSplitDestination(remaining)

distribute( ) getRandomCard( )

addCard(card)

getRandomCard( )

addCard(card)

getRandomCard( )

addCard(card)

getRandomCard( )

addCard(card)

getRandomCard( )

addCard(card)

addDestination(hand2, 1)

Figura 30. Modelagem dinâmica da distribuição de cartas.

Criação de um Jogo

A criação do jogo consiste em especializar a classe CardGame implementando os

seguintes métodos abstratos:

• createPiles – inicializar as pilhas do jogos, que devem estar previamente

definidas.

• createPlayers – inicializar os atributos dos jogadores.

• distributeCards – criar o baralho a ser usado no jogo e o distribuidor de

cartas. Distribuir as cartas.

• createInterface – criar a interface para o jogo definido, painéis necessários,

layouts, etc.

Page 55: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

55

Figura 31. Classe Básica de um jogo de cartas.

5.3 Implementação

Durante a implementação usou-se o ambiente de desenvolvimento Jbuilder 7

Enterprise Edition juntamente com o SDK Java 1.4. O código está disponível no CD em

anexo ou no site http://www.inf.ufsc.br/~ricardo/magic/

5.4 Testes

Aplicações teste foram desenvolvidas para avaliar a capacidade do framework de

facilitar o desenvolvimento de aplicações no domínio proposto. Além de validar o

framework para jogos de cartas, as aplicações teste serviram também para validar o

framework para interface gráfica.

FreeCell

O FreeCell é um jogo de cartas simples e muito popular. O objetivo do jogo é

ordenar as cartas em quatro pilhas, uma para cada naipe. Existem três tipos de pilhas de

carta nesse jogo:

• Destinos – existem quatro pilhas desse tipo, uma para cada naipe. Todas as

cartas devem estar em um destino para que o jogo acabe.

o Condição de entrada – as cartas devem ser adicionadas em ordem

crescente e todas as cartas de um destino devem ser do mesmo naipe.

o Condição de saída – depois de adicionada em um destino, uma carta

não pode ser retirada.

• Espaços – essas pilhas são usadas para armazenar temporariamente uma carta

Page 56: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

56

durante o jogo. O número de espaços é configurável.

o Condição de entrada – qualquer carta pode ser adicionada em um

espaço, independentemente de seu naipe ou número. Entretanto, cada

espaço comporta no máximo uma carta.

o Condição de saída – uma carta sempre pode ser retirada de um espaço.

• Pilhas de jogo – essas pilhas são usadas para movimentar as cartas durante o

jogo. O número de pilhas desse tipo é configurável.

o Condição de entrada – as cartas devem ser adicionadas em ordem

decrescente. A carta adicionada deve ser de cor diferente da última

carta na pilha.

o Condição de saída – somente a última carta da pilha pode ser retirada.

Inicialmente, as cartas do baralho são distribuídas de forma aleatória entra as pilhas

de jogo.

Figura 32. Screenshot do jogo FreeCell.

Paciência

Esse é o jogo mais jogado no mundo. Assim como no FreeCell, o objetivo desse jogo

Espaços Destinos

Pilhas de jogo

Page 57: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

57

é ordenar as cartas por naipe. Existem três tipos de pilhas de carta nesse jogo:

• Pilha de compra – essa pilha armazena as carta que ainda não entraram no

jogo.

o Condição de entrada – nenhuma carta pode ser adicionada nessa pilha.

o Condição de saída – uma carta sempre pode ser retirada dessa pilha.

• Destinos – existem quatro pilhas desse tipo, uma para cada naipe. Todas as

cartas devem estar em um destino para que o jogo acabe.

o Condição de entrada – as cartas devem ser adicionadas em ordem

crescente e todas as cartas de um destino devem ser do mesmo naipe.

o Condição de saída – a carta do topo de uma pilha desse tipo sempre

pode ser removida.

• Pilhas de jogo – essas pilhas são usadas para movimentar as cartas durante o

jogo. O número de pilhas desse tipo é configurável.

o Condição de entrada – as cartas devem ser adicionadas em ordem

decrescente. A carta adicionada deve ser de cor diferente da última

carta na pilha.

o Condição de saída – um conjunto de cartas pode ser retirado do final

dessa pilha desde que elas estejam em ordem decrescente e sejam de

cores intercaladas.

As cartas são distribuídas entre as pilhas de jogo, uma para a primeira pilha, duas

para a segunda, etc. As cartas restantes são adicionadas na pilha de compra.

Page 58: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

58

Figura 33. Screenshot do jogo Paciência.

5.5 Documentação

A documentação do framework para jogos de carta foi elaborada de maneira similar

à documentação do framework para interface gráfica. A seção 4.5 descreve em detalhes as

fontes de documentação.

Pilha de compra Destinos

Pilhas de jogo

Page 59: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

59

6. Conclusões

A estrutura de classes de um framework, bem como o modelo de colaboração entre

essas classes, é bastante complexa. Projetar e implementar essa estrutura exige um alto

nível de conhecimento das técnicas e ferramentas para projeto e desenvolvimento OO. Por

essa razão, desenvolver um framework abrangente e extensível é um ótimo exercício

dessas técnicas.

Além disso, o desenvolvimento de aplicações sob um framework explicita a

importância do reuso. Um framework bem abrangente facilita muito o desenvolvimento de

aplicações no domínio tratado.

Entretanto, o desenvolvimento de um framework exige um esforço bem maior do que

o desprendido para criar uma aplicação isolada. Uma análise detalhada do domínio alvo e

da relação custo beneficio do desenvolvimento de um framework deve fazer parte da

análise de requisitos de um projeto qualquer que tencione criar um framework para um

domínio específico.

Os padrões de projeto, utilizados durante a modelagem e implementação dos

frameworks descritos nesse documento, são referências importantíssimas no

desenvolvimento de aplicações OO. Além de facilitar o projeto e implementação, os

padrões são uma boa fonte de documentação para a interação entre classes de um

subsistema de uma aplicação OO qualquer.

Page 60: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

60

7. Sugestões de Trabalhos Futuros

Apesar de facilitar o desenvolvimento de aplicações no domínio tratado, o uso de

frameworks exige um certo conhecimento técnico. É necessário conhecer técnicas de

projeto e desenvolvimento para criar aplicações sob um framework. É difícil para um

usuário leigo que queira desenvolver aplicações entender a estrutura de classes de um

framework e até mesmo a documentação que geralmente é disponibilizada. De forma a

facilitar o uso dos frameworks desenvolvidos, seria de grande valia a criação de

cookbooks que explicassem com detalhes como criar aplicações para cada um dos

frameworks desenvolvidos.

Além disso, a criação de um ambiente gráfico para o desenvolvimento de aplicações

possibilitaria que um maior número de pessoas se beneficiassem das vantagens do uso de

um framework. Existem diversos ambientes para a criação de interfaces gráficas nas mais

diferentes linguagens. O IDE JBuilder por exemplo, disponibiliza um ambiente para

facilitar o uso do framework AWT do Java. Criar um ambiente para os frameworks

propostos não seria uma tarefa simples, entretanto este é um requisito para que os

framework se popularizem.

Sabemos, também, que o ciclo de vida de um framework é retroativo. À medida que

novas aplicações são desenvolvidas surgem características do domínio que não foram

cobertas pelo framework. Algumas oportunidades de refinamento foram descobertas

durante a validação, isto é, criação de aplicações, dos frameworks propostos:

Framework para Interface Gráfica

• Adicionar suporte a elementos básicos de uma GUI – elementos como botões,

caixas de texto, menus, barras de rolagem, etc. são importantes no

desenvolvimento de qualquer aplicação sob um framework para GUI.

• Adicionar suporte a transparência na classe View – a possibilidade de criar

visões transparentes melhoraria o desempenho do processo de desenho além

de abrir mais uma opção para que o desenvolvedor de aplicações crie visões

para seus modelos.

Page 61: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

61

Framework para Jogos de Cartas

• Adicionar suporte a rede – a possibilidade de jogar em rede é uma

característica que está cada vez mais presente nos jogos de cartas. Criar uma

estrutura que suporte essa característica é imprescindível.

• Adicionar uma estrutura para gerencias turnos – vários jogos de cartas que

envolvem mais de um jogador são baseados em turnos. Cada jogador joga no

seu turno e geralmente não podem efetuar ações no turno dos adversários.

Essa é uma característica importante ainda não coberta pelo framework para

jogos de carta proposto.

Page 62: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

62

8. Referências Bibliográficas

[DOU 99] DOUGLASS, B. P. Doing Hard Time: Developing Real-Time Systems with

UML, Objects, Frameworks, and Patterns. [s.l.]: Addison Weasley, 1999.

[FAY 99] FAYAD, M. et al. Building Application Frameworks. New York: Wiley,

1999.

[GAM 99] GAMMA, E. Design patterns: elements of reusable object-oriented software.

Reading: Addison Wesley, 1994.

[LEW 95] LEWIS, T. et al. Object-oriented application frameworks. Greenwich:

Manning, 1995.

[MEY 97] MEYER, B. Object-oriented software construction. 2 ed. [s.l.]: Prentice Hall

PTR, 1997.

[SIL 98] SILVA, R. P.; PRICE, R. T. A busca de generalidade, flexibilidade e

extensibilidade no processo de desenvolvimento de frameworks

orientados a objetos. In: WORKSHOP IBEROAMERICANO DE

ENGENHARIA DE REQUISITOS E AMBIENTES DE SOFTWARE,

(IDEAS), 1998, Torres. Anais... Porto Alegre: Instituto de Informática /

UFRGS, 1998. v.2, p298-309.

[SIL 00] SILVA, R. P. Suporte ao desenvolvimento e uso de frameworks e

componentes. Porto Alegre: Instituto de Informática / UFRGS, 2000.

Page 63: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

63

9. Apêndices

9.1 Guia para a criação de aplicações

Hot Spots – Framework de interface gráfica

A seguir estão expostos os hot spots identificados nos diagramas do framework de

interface gráfica.

Para a criação de um novo modelo o usuário do framework pode utilizar como super

classe qualquer elemento da hierarquia de classes Model. Deve-se tomar o cuidado de, a

cada mudança efetuada no modelo, seja por chamada de seus métodos ou em decorrência

de algum evento interno, chamar a função notifyViewers() para permitir que as visões

sejam atualizadas. Deve-se também tomar o cuidado de garantir que o estado do objeto

seja consistente no momento da chamada, pois nesse momento qualquer método pode ser

chamado sem o controle explícito do modelo. É recomendado que o objeto changeInfo seja

utilizado para informar de forma precisa qual mudança que ocorreu.

Model

notifyViewers(changeInfo : Object) : void

Existem dois casos em que uma nova View deve ser criada. O primeiro ocorre

quando um novo modelo é criado e se deseja mostrá-lo de forma gráfica; o segundo,

quando se deseja criar um novo tipo de visualização para um modelo já existente. Ambos

são equivalentes no passo de criação da View e diferem apenas na definição do

ViewFactory que será usado.

Existem 4 métodos que precisam ser redefinidos numa nova visão:

• isCompatible(): deve verificar se o modelo a ser utilizado por uma View é

compatível com esta.

• modelChanged(): deve atualizar qualquer dado sobre o modelo que é mantido

dentro da View.

Page 64: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

64

• alwaysRepaintAll(): retorna um valor booleano que identifica se uma

operação de desenho (drawArea()) pode ser efetuada apenas em parte do

objeto ou se o mecanismo de desenho implementado suporta apenas o

redesenho de toda a área. Possui implementação padrão que retorna true. Só

deve ser mudado por razões de desempenho.

• drawArea(): responsável por desenhar a visão. Possui um parâmetro que

identifica qual área deve ser desenhada (será sempre a área total do objeto se

alwaysRepaintAll() retornar verdadeiro).

• calculatePreferredSize(): deve retornar o tamanho preferido para as

dimensões do objeto. Esse valor é usado pelos gerenciadores de disposição

como referência e é recalculado sempre que o modelo muda, reorganizando o

layout quando o valor mudar.

View

alwaysRepaintAll()calculatePreferredSize()drawArea()modelChanged()isCompatible()

Após a criação da visão, os ViewFactorys devem ser atualizados para criarem visões

do novo tipo. No caso de uma visão para um modelo novo, o DefaultViewFactory deve ser

atualizado11 para incluir o novo tipo. Caso a visão feita seja para um modelo já existente e

que já possua uma View, o DefaultViewFactory deve ser atualizado caso a nova visão

passe a ser a padrão ou um novo ViewFactory deve ser criado para ser usado em um

contexto específico (como um painel dentro da interface).

ViewFactory

createViewFor(model : Model) : View

Aplicações em geral utilizarão a classe PanelModel como forma de colocar modelos

de forma hierárquica dentro da interface com o usuário. Um dos itens configuráveis neste

11 Veja documentação no JavaDocs para mais detalhes.

Page 65: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

65

caso é qual gerenciador de disposição será usado. Vários gerenciadores já estão pré-

definidos, porém, o usuário pode definir novos, se necessário, criando uma subclasse de

LayoutManager.

Para isso o método doLayout() deve ser implementado, atribuindo para cada View do

painel sua nova posição e tamanho. Esse método deve calcular as novas posições

baseando-se apenas no tamanho do painel e no valor retornado por getPreferredSize() de

cada View. Também deve ser redefinido o método getPreferredSize() no layout, retornando

as dimensões necessárias para acomodar as visões dentro do painel da melhor forma

possível.

LayoutManager

doLayout()getPreferedSize()

Hot Spots – Framework de interface gráfica

A seguir estão expostos os hot spots identificados nos diagramas do framework de

jogos de cartas.

Diferentes jogos de cartas podem usar cartas de tipos diferentes. Caso isso seja

necessário, uma subclasse de Card deve ser implementada, juntamente com uma View

específica para esse tipo de carta. Card é uma subclasse de AttributedModel, logo todo

atributo a ser implementado pela classe deve ser adicionado utilizando o método

addAttribute(). Deve ser definido também qual modelo representa o fundo da carta. Em

geral esse modelo restringe-se a uma figura, porém itens mais complexos podem ser

utilizados.

Card

addAttribute()getAttribute()getBackModel()

Cada jogo pode utilizar um subconjunto das possibilidades possíveis em um

Page 66: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

66

determinado tipo de carta (apenas cartas de copas, por exemplo) e portanto Decks

específicos podem ser criados para um determinado jogo. A criação de um novo Deck

consiste apenas na criação de uma subclasse de Deck que implementa o método fillDeck()

adicionando todas as cartas pertencentes na lista interna.

Deck

fillDeck()

Também pode ser necessária a definição de um novo tipo de distribuição de cartas

para um jogo específico. Nada é assumido com relação à fonte dessas cartas nem qual o

destino delas, por isso apenas o método distribute() precisa ser implementado. Porém é

esperado que uma implementação de CardDistributor utilize Decks como fonte e

SetOfCards como destino, de forma a manter compatibilidade com o resto da estrutura.

CardDistributor

distribute()

A classe PileOfCards utiliza condições para a entrada e para a saída de cartas. Essas

condições são utilizadas para implementar as regras em um jogo de cartas.Os dois métodos

disponíveis devem ser implementados em uma subclasse. O primeiro corresponde apenas à

tentativa de adição/remoção de uma única carta e o segundo a adição/remoção de um

conjunto seqüencial de cartas. Os parâmetros fornecidos podem ser utilizados para obter

mais informações antes de decidir pelo resultado do teste.

AddCardCondition

testAdd(card : Card, source : PileOfCards, destinationIndex : int, destination : PileOfCards) : booleantestAdd(cards : PileOfCards, source : PileOfCards, destinationStartIndex : int, destination : PileOfCards) : boolean

RemoveCardCondition

testRemove(card : Card, sourceIndex : int, source : PileOfCards) : booleantestRemove(cards : PileOfCards, sourceStartIndex : int, source : PileOfCards) : boolean

Page 67: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

67

10. Anexos

10.1 Código Fonte

O código fonte do framework está disponível no CD em anexo. O código fonte das

aplicações desenvolvidas está exposto abaixo.

Paciência

import conditions.add.*; import conditions.remove.*; import java.awt.Rectangle; public class Solitaire extends CardGame { protected class InOrderSpecificSuitAddCondition extends CompositeAddCondition { public InOrderSpecificSuitAddCondition() { addCondition(new InOrderAddCondition()); addCondition(new SpecificSuitAddCondition()); } public InOrderSpecificSuitAddCondition(int allowedSuit) { addCondition(new InOrderAddCondition()); addCondition(new SpecificSuitAddCondition(allowedSuit)); } } protected class ToggleColorInOrderAddCondition extends CompositeAddCondition { public ToggleColorInOrderAddCondition() { addCondition(new InOrderAddCondition(false)); addCondition(new ToggleColorAddCondition()); } } protected class ToggleColorInOrderOnlyLastCardsRemoveCondition extends CompositeRemoveCondition { public ToggleColorInOrderOnlyLastCardsRemoveCondition() { addCondition(new InOrderRemoveCondition(false)); addCondition(new OnlyLastCardsRemoveCondition()); addCondition(new ToggleColorRemoveCondition()); addCondition(new OnlyFaceUpRemoveCondition()); } }

Page 68: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

68

public class DrawPileEventHandler extends CommonMouseEventHandler { PileOfCards pileOfCards; public DrawPileEventHandler (PileOfCards pileOfCards) { this.pileOfCards = pileOfCards; } protected void mouseDown(View sender, MouseEvent event) { } protected void mouseUp(View sender, MouseEvent event) { // empty } protected void mouseClick(View sender, MouseEvent event) { Card card = pileOfCards.getLastCard(); pileOfCards.removeLastCard(); pileOfCards.addCard(0, card); } protected void mouseDoubleClick(View sender, MouseEvent event) { mouseClick(sender, event); } protected void mouseMove(View sender, MouseEvent event) { // empty } protected void mouseEnter(View sender, MouseEvent event) { // empty } protected void mouseExit(View sender, MouseEvent event) { // empty } } public class GamePileEventHandler extends CommonMouseEventHandler { PileOfCards pileOfCards; public GamePileEventHandler(PileOfCards pileOfCards) { this.pileOfCards = pileOfCards; } protected void mouseDown(View sender, MouseEvent event) { } protected void mouseUp(View sender, MouseEvent event) {

Page 69: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

69

// empty } protected void mouseClick(View sender, MouseEvent event) { if (sender.getModel() == pileOfCards.getLastCard()) { Card card = pileOfCards.getLastCard(); card.setFaceUp(true); } } protected void mouseDoubleClick(View sender, MouseEvent event) { mouseClick(sender, event); } protected void mouseMove(View sender, MouseEvent event) { // empty } protected void mouseEnter(View sender, MouseEvent event) { // empty } protected void mouseExit(View sender, MouseEvent event) { // empty } } public static void main(String args[]) { Solitaire game = new Solitaire(7); game.initialize(); } protected PileOfCards drawPile; protected PileOfCards destinations[] = new PileOfCards[4]; protected int numberOfGamePiles; protected PileOfCards gamePiles[]; public Solitaire(int numberOfGamePiles) { this.numberOfGamePiles = numberOfGamePiles; } public void createInterface() { // a panel for the destination piles PanelModel destinationsPanel = new PanelModel(new SpacedLayout(SpacedLayout.ORIENTATION_HORIZONTAL, 20, SpacedLayout.ALIGN_LEFT, false, false, false)); for (int i = 0; i < destinations.length; i++) { destinationsPanel.addModel(destinations[i], null);

Page 70: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

70

} // and one for the game piles PanelModel piles = new PanelModel(new SpacedLayout(SpacedLayout.ORIENTATION_HORIZONTAL, 20, SpacedLayout.ALIGN_LEFT, false, false, false)); for (int i = 0; i < gamePiles.length; i++) { piles.addModel(gamePiles[i], null); } // a panel to group the draw pile and the destination piles PanelModel topPanel = new PanelModel(new SpacedLayout(SpacedLayout.ORIENTATION_HORIZONTAL, 260, SpacedLayout.ALIGN_TOP, false, false, false)); topPanel.addModel(drawPile, null); topPanel.addModel(destinationsPanel, null); // our surface PanelModel surface = new PanelModel(new SpacedLayout(SpacedLayout.ORIENTATION_VERTICAL, 10, SpacedLayout.ALIGN_TOP, false, false, false)); surface.addModel(topPanel, null); surface.addModel(piles, null); // and, finally, our frame Frame frame = new Frame(surface, "Paciência"); frame.setBounds(new Rectangle(0, 0, 850, 400)); frame.centerInScreen(); frame.setVisible(true); } public void distributeCards() { //Deck mainDeck = new FourSuitDeck("D:/JStuff/CARDDECK/CARDS-DE"); Deck mainDeck = new FourSuitDeck("solitaire"); StandardCardDistributor cardDistributor = new StandardCardDistributor(); cardDistributor.setSource(mainDeck); for (int i = 0; i < gamePiles.length; i++) { cardDistributor.addDestination(gamePiles[i], i, false); cardDistributor.addDestination(gamePiles[i], 1, true); } cardDistributor.addSplitDestination(drawPile); try { cardDistributor.distribute(); } catch (NotEnoughCardsException exp) {

Page 71: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

71

System.err.println("Error distributing card."); } } public void createPiles() { // card holders conditions OnlyLastCardsRemoveCondition drawPileRemoveCondition = new OnlyLastCardsRemoveCondition(); FalseAddCondition drawPileAddCondition = new FalseAddCondition(); // creating our draw pile drawPile = new PileOfCards(PileOfCards.LAYOUT_TYPE_PILE, true); drawPile.setAddCondition(drawPileAddCondition); drawPile.setRemoveCondition(drawPileRemoveCondition); drawPile.setDefaultEventHandler(new DrawPileEventHandler(drawPile)); // destinations remove condition // we have to create a new add condition for each destination OnlyLastCardsRemoveCondition destinationsRemoveCondition = new OnlyLastCardsRemoveCondition(); // our destinations for (int i = 0; i < destinations.length; i++) { destinations[i] = new PileOfCards(PileOfCards.LAYOUT_TYPE_PILE, true); destinations[i].setAddCondition(new InOrderSpecificSuitAddCondition()); destinations[i].setRemoveCondition(destinationsRemoveCondition); } ToggleColorInOrderAddCondition gamePilesAddCondition = new ToggleColorInOrderAddCondition(); ToggleColorInOrderOnlyLastCardsRemoveCondition gamePilesRemoveCondition = new ToggleColorInOrderOnlyLastCardsRemoveCondition(); // and our game piles gamePiles = new PileOfCards[numberOfGamePiles]; for (int i = 0; i < gamePiles.length; i++) { gamePiles[i] = new PileOfCards(PileOfCards.LAYOUT_TYPE_VERTICAL, false); gamePiles[i].setAddCondition(gamePilesAddCondition); gamePiles[i].setRemoveCondition(gamePilesRemoveCondition); gamePiles[i].setChainRemoval(true); gamePiles[i].setDefaultEventHandler(new GamePileEventHandler(gamePiles[i])); } } public void createPlayers() { // empty }

Paciência

Page 72: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

72

import conditions.add.*; import conditions.remove.*; import java.awt.Rectangle; public class FreeCell extends CardGame { protected class InOrderSpecificSuitAddCondition extends CompositeAddCondition { public InOrderSpecificSuitAddCondition() { addCondition(new InOrderAddCondition()); addCondition(new SpecificSuitAddCondition()); } public InOrderSpecificSuitAddCondition(int allowedSuit) { addCondition(new InOrderAddCondition()); addCondition(new SpecificSuitAddCondition(allowedSuit)); } } protected class ToggleColorInOrderAddCondition extends CompositeAddCondition { public ToggleColorInOrderAddCondition() { addCondition(new InOrderAddCondition(false)); addCondition(new ToggleColorAddCondition()); } } public static void main(String args[]) { FreeCell game = new FreeCell(8, 4); game.initialize(); } protected int numberOfCardHolders; protected PileOfCards cardHolders[]; protected PileOfCards destinations[] = new PileOfCards[4]; protected int numberOfGamePiles; protected PileOfCards gamePiles[]; public FreeCell(int numberOfGamePiles, int numberOfCardHolders) { this.numberOfGamePiles = numberOfGamePiles; this.numberOfCardHolders = numberOfCardHolders; } public void createInterface() { // a panel for the destination piles PanelModel destinationsPanel = new PanelModel(new SpacedLayout(SpacedLayout.ORIENTATION_HORIZONTAL, 10, SpacedLayout.ALIGN_TOP, false, false, false));

Page 73: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

73

for (int i = 0; i < destinations.length; i++) { destinationsPanel.addModel(destinations[i], null); } // another one for the card holders PanelModel holdersPanel = new PanelModel(new SpacedLayout(SpacedLayout.ORIENTATION_HORIZONTAL, 10, SpacedLayout.ALIGN_TOP, false, false, false)); for (int i = 0; i < cardHolders.length; i++) { holdersPanel.addModel(cardHolders[i], null); } // and one for the game piles PanelModel piles = new PanelModel(new SpacedLayout(SpacedLayout.ORIENTATION_HORIZONTAL, 10, SpacedLayout.ALIGN_TOP, false, false, false)); for (int i = 0; i < gamePiles.length; i++) { piles.addModel(gamePiles[i], null); } // a panel to group the card holders and the destination piles PanelModel topPanel = new PanelModel(new SpacedLayout(SpacedLayout.ORIENTATION_HORIZONTAL, 90, SpacedLayout.ALIGN_LEFT, false, false, false)); topPanel.addModel(holdersPanel, null); topPanel.addModel(destinationsPanel, null); // our surface PanelModel surface = new PanelModel(new SpacedLayout(SpacedLayout.ORIENTATION_VERTICAL, 20, SpacedLayout.ALIGN_MIDDLE, false, false, false)); surface.addModel(topPanel, null); surface.addModel(piles, null); // and, finally, our frame Frame frame = new Frame(surface, "FreeCell"); frame.setBounds(new Rectangle(0, 0, 850, 400)); frame.centerInScreen(); frame.setVisible(true); } public void distributeCards() { Deck mainDeck = new FourSuitDeck("freecell"); StandardCardDistributor cardDistributor = new StandardCardDistributor(); cardDistributor.setSource(mainDeck); for (int i = 0; i < gamePiles.length; i++) {

Page 74: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

74

cardDistributor.addSplitDestination(gamePiles[i]); } try { cardDistributor.distribute(); } catch (NotEnoughCardsException exp) { System.err.println("Error distributing card."); } } public void createPiles() { // card holders conditions TrueRemoveCondition holdersRemoveCondition = new TrueRemoveCondition(); MaxNumberOfCardsAddCondition holdersAddCondition = new MaxNumberOfCardsAddCondition(1); // creating our card holders cardHolders = new PileOfCards[numberOfCardHolders]; for (int i = 0; i < cardHolders.length; i++) { cardHolders[i] = new PileOfCards(PileOfCards.LAYOUT_TYPE_PILE, true); cardHolders[i].setAddCondition(holdersAddCondition); cardHolders[i].setRemoveCondition(holdersRemoveCondition); } // destinations remove condition // we have to create a new add condition for each destination FalseRemoveCondition destinationsRemoveCondition = new FalseRemoveCondition(); // our destinations for (int i = 0; i < destinations.length; i++) { destinations[i] = new PileOfCards(PileOfCards.LAYOUT_TYPE_PILE, true); destinations[i].setAddCondition(new InOrderSpecificSuitAddCondition()); destinations[i].setRemoveCondition(destinationsRemoveCondition); } ToggleColorInOrderAddCondition gamePilesAddCondition = new ToggleColorInOrderAddCondition(); OnlyLastCardsRemoveCondition gamePilesRemoveCondition = new OnlyLastCardsRemoveCondition(); // and our game piles gamePiles = new PileOfCards[numberOfGamePiles]; for (int i = 0; i < gamePiles.length; i++) { gamePiles[i] = new PileOfCards(PileOfCards.LAYOUT_TYPE_VERTICAL, true); gamePiles[i].setAddCondition(gamePilesAddCondition); gamePiles[i].setRemoveCondition(gamePilesRemoveCondition); // gamePiles[i].setRemoveCondition(new TrueRemoveCondition()); gamePiles[i].setChainRemoval(false);

Page 75: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

75

} } public void createPlayers() { // empty } }

Page 76: MAGIC: Um framework para jogos de cartas - inf.ufsc.brricardo/magic/relatorio.pdf · A utilização de um framework tem como objetivo a redução no tempo e no custo de criação

76

Artigo