Resumo de TCC: MAGIC: Um framework para jogos de cartas http://www.lisha.ufsc.br/~robert/tcc/relatorio.pdf Autores: André Luís Knabben Thiago Robert Orientador: Professor Doutor Ricardo Pereira e Silva Submetido à banca em: 2002 / 1 Ademir Coelho 0213800-0 Florianópolis, 21 de fevereiro de 2006.
Sumário Sumário...2 Introdução...3 Frameworks Orientados a Objetos...4 Desenvolvimento de Frameworks...5 Análise do Domínio...5 Modelagem...5 Implementação...5 Testes...6 Documentação...6 Padrões de Projeto...7 Framework para Interface Gráfica...8 Análise do Domínio...8 Projeto...8 Implementação...9 Testes...9 Documentação...9 Framework para Jogos de Cartas...10 Análise do Domínio...10 Projeto...10 Hierarquia de Classes Card...10 PileOfCards...11 Criação de um Jogo...11 Implementação...12 Testes...12 FreeCell...12 Paciência...12 Documentação...12 Conclusões...13 Sugestões de Trabalhos Futuros...14 2
Introdução Há décadas, a reusabilidade vem sendo uma das principais metas dos engenheiros de software. Entretanto, reusar software não é nada simples. Com a popularização do paradigma OO, tornou-se possível desenvolver componentes reusáveis de maior granularidade, entre eles os frameworks OO. 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. O tema proposto é o desenvolvimento de frameworks com o uso de padrões de projeto, onde este será trabalhado através do desenvolvimento de um framework específico para jogos de carta. 3
Frameworks Orientados a Objetos 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. 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. A inversão de controle permite que o framework (e não a aplicação) determine que métodos invocar em resposta a eventos. 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. 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. 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. Implementação A implementação de frameworks segue as linhas gerais da implementação de uma aplicação comum. É 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. 5
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. 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. Frameworks podem ser descritos a partir de notações de metodologia de Análise e Projeto Orientados a Objetos como, por exemplo, a UML. 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 concentrandose na descrição do processo de criação de aplicações sob o framework. 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. 6
Padrões de Projeto 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. 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. Padrão 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. Padrão 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. 7
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. Análise do Domínio 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, as principais fontes de referência foram os pacotes AWT/SWING do Java 1.4. Projeto Foi utilizado o padrão MVC (Model-View-Controller), onde 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. 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. 8
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, as Views são automaticamente criadas pelo sistema. Implementação Durante a implementação usou-se o ambiente de desenvolvimento Jbuilder 7. 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. 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. 9
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. Análise do Domínio Analisando várias aplicações 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. 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 das diferentes 10
pilhas encontradas nos jogos, como, por exemplo, a mão de um jogador ou a pilha de compra. 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 de classes em que seus métodos são invocados sempre que o usuário tenta remover uma carta de algum PileOfCards e quando ele tenta adiciona-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). 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. Criação de um Jogo A criação do jogo consiste em especializar a classe CardGame implementando os seguintes métodos abstratos: 11
createpiles inicializar as pilhas do jogo, 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. Implementação Durante a implementação usou-se o ambiente de desenvolvimento Jbuilder 7. 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. Paciência Esse é o jogo mais jogado no mundo. Assim como no FreeCell, o objetivo desse jogo é ordenar as cartas por naipe. Documentação A documentação do framework para jogos de carta foi elaborada de maneira similar à documentação do framework para interface gráfica. 12
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. 13
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. 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. Sabemos, também, que o ciclo de vida de um framework é retroativo. 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. 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. 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. 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. 14