• Aucun résultat trouvé

CICS/VS PROGRAM DESIGN

Dans le document Program Product (Page 25-29)

Após estudos e testes para compreensão do funcionamento da arquitetura MVC, foi iniciada a refatoração do código existente e a implementação das estruturas necessárias ao funcionamento do código.

Como já foi descrito na seção 3.3.1, o padrão MVC utiliza uma estrutura de modelo de domínio, visões e controladores. Além dessas, uma camada contendo regras de negócio também pode existir. Essas partes se comunicam através de mensagens entre seus objetos, para desempenharem seus papéis.

Ao definir a forma inicial e separar as responsabilidades das classes, foram criados diretórios que correspondem às partes integrantes da arquitetura. Na figura 16 é mostrada a estrutura dividida.

Figura 16 - Estrutura de diretórios do MVC

Fonte: autoria própria

Como padrão da linguagem C++, existem dois tipos de arquivo, os que contém a declaração dos métodos, que possuem a extensão .h, e os que contém o código-fonte dos métodos, com a extensão .cpp.

Os arquivos de código ficam dentro do diretório source (src) e, seguindo a estruturação arquitetural, são divididos em controlador, modelo, visão e serviço. Os arquivos contendo apenas a declaração dos métodos ficam dentro de include. Eles também seguiram a separação da arquitetura. Separar o código dessa maneira auxilia na criação de novas funcionalidades e também no gerenciamento da aplicação.

Após decidir sobre as responsabilidades, iniciou-se a codificação das classes fundamentais ao domínio da aplicação. A primeira classe construída foi Nota, já que ela contém as informações fundamentais para o programa. Na figura 17 são mostrados os atributos da classe Nota.

Fonte: autoria própria

Nota é a informação de domínio extraída junto ao especialista no assunto. Esse é o dado que estrutura as funcionalidades do C-Syncker. Inicialmente as qualidades eram representadas apenas por tipos primitivos como inteiros e cadeias de caracteres. Contudo, foi percebido que essa representação era limitada e que prejudicava a execução das operações do programa, pois estas, geralmente, possuíam duas versões (uma para manipular inteiros e outra para cadeias de caracteres).

Assim, após muitas discussões e estudos sobre modelagem de problemas com orientação a objetos, uma melhor forma de representar as qualidades foi encontrada, resultando em Nota. Pesquisas posteriores mostraram que essa solução se assemelha bastante ao que foi proposto no padrão musicXML, facilitando uma conversão futura entre os dois tipos de dados.

Também foi necessária uma decisão sobre a implementação da classe que manipula os dados. Como a aplicação não utiliza um banco de dados, foi criada uma classe que simula o comportamento de um. A NotaDAO se encarrega de realizar as operações de banco, usando um dicionário de dados para armazenar informações. Na figura 18 é mostrada uma visão da classe.

Figura 18 - Classe NotaDAO e seus métodos

Fonte: autoria própria

Os principais pontos a se perceber na figura 18 são (1) a herança da classe com o Modelo, evidenciando sua existência como parte do modelo do sistema, (2) uma entidade do tipo mapa ou dicionário, que simula o banco de dados e (3) os métodos de manipulação das informações.

A classe Modelo também foi implementada e suas funções são, na primeiro versão, identificar quem pertence ao domínio da aplicação e ser a interface que implementa o padrão observador para notificar ao usuário mudanças nos dados. Na figura 19 é mostrada a declaração da classe.

Figura 19 - Classe Modelo

Fonte: autoria própria

Na estrutura mostrada na figura 19 existe uma lista que registra os chamados “observadores”. Essas classes precisam ser atualizadas sobre as mudanças que ocorrem no banco de dados.

métodos virtuais, o que torna o Modelo uma classe abstrata. Assim, seu comportamento apenas pode ser herdado por outras classes. Os métodos adicionam interessados na lista de observadores e notificam as alterações ocorridas. Os métodos abaixo de notifiqueMudancas() fazem parte do padrão DAO (ver seção 2.2.4), que define uma interface comum para acesso ao banco. Assim, as classes que fazem herança com Modelo, precisam definir suas formas de salvar, ler e deletar registros de um banco, permitindo que diferentes tecnologias sejam usadas através da mesma interface.

Após implementar as classes de domínio e o banco de dados virtual, foi decidido que as classes de visualização e de entrada de dados seriam as próximas. (Essa ordem de realização não é obrigatória, apenas entendeu-se que elas seriam necessárias para fazer testes de funcionamento da aplicação quando ela estivesse funcional.)

Como as visões pertencem a uma estrutura do MVC, foi definida a classe abstrata Visao, que possui métodos necessários a todas as outras classes responsáveis por visualização de dados. Na figura 20 é mostrada a declaração da estrutura Visao.

Figura 20 - Classe Visao

Fonte: autoria própria

A classe Visao necessita de algumas estruturas para desempenhar suas funções. Ela faz herança com a classe Observador o que implica que ela pode se registrar como interessada em receber notificações sobre mudanças no banco. Nessa classe existem dois métodos (semelhante ao Modelo) que desempenham o papel de registrar classes interessadas em atualizações e notificar mudanças. Em particular para essa classe e suas derivadas, a notificação enviada é um sinal, que representa qual ação foi realizada pelo usuário.

As ações que podem ser realizadas dentro da Visao estão registradas dentro da estrutura “enum” e se referem a seleção de um menu ou seleção de um item de menu. Essas sinalizações são importantes pois elas serão enviadas aos controladores, que são os observadores da classe, e permitirão que o controlador identifique a opção do usuário e destine o tratamento apropriado.

Após definir a classe mais alta na hierarquia das visões, foi iniciada a codificação das classes de menus textuais. Como os menus da aplicação possuem comportamentos semelhantes, foi construída uma estrutura que possui os métodos e atributos comuns. Na figura 21 é mostrada a declaração da classe Menu.

Figura 21 - Classe Menu

Fonte: autoria própria

A classe Menu faz herança com a Visao, o que permite o envio de notificações sobre ações do usuário para objetos registrados e também permite receber notificações de mudanças no banco. Menu define métodos para ler as entradas de dados do usuário, desenhar os elementos do menu na tela, adicionar ou remover elementos no menu, podendo ser, inclusive, outro menu, e formas de saber qual foi o item selecionado pelo usuário. Esses comportamentos são comuns a esse tipo de componente, portanto, os menus do programa são herdeiros dessa classe.

Ao finalizar a estrutura base Menu, foi criado o MenuGeral, chamado quando a aplicação é inicializada. Ele mostra quais as opções o usuário tem dentro do C- Syncker para entrar com dados, escolher operações ou ver resultados. Na figura 22 é mostrada a definição da classe.

Fonte: autoria própria

O MenuGeral faz herança com o Menu para herdar os comportamentos comuns. Os métodos necessários são sobrescritos, ou seja, possuem seu comportamento alterado para corresponder às necessidades da classe.

O MenuDados, mostrado na figura 23, faz herança com Menu. Seguindo o que foi feito em MenuGeral, ocorre aqui a sobrescrita de métodos virtuais para adequar ao comportamento da visão. Essa classe possui as opções relacionadas a entrada de dados no programa.

Figura 23 - Classe MenuDados

O MenuOperacoes é responsável por apresentar ao usuário as operações que podem ser realizadas pelo C-Syncker. Na figura 24 é mostrada a definição da classe.

Figura 24 - Classe MenuOperacoes

Fonte: autoria própria

A estrutura de MenuOperacoes é a mesma de MenuDados, faz herança com a classe Menu e sobrescreve os métodos para refletir as necessidades do menu.

O MenuResultados é a classe que exibe para o usuário quais são as opções disponíveis de saídas do programa, desde gerar arquivos PDF de partitura até MIDIs e valores em tela. Na figura 25 é mostrada a definição da classe.

Fonte: autoria própria

A classe MenuResultados possui a mesma estrutura das demais classes de menu. Além disso, ela apresenta um método diferente da interface comum cuja responsabilidade é mostrar na tela os elementos de uma lista.

O comportamento das classes de menu tem varia pouco. Esse comportamento padronizado auxilia quando há necessidade de trocar a visão que está na tela, caso seja necessário e se um controlador puder ter mais de uma visão relacionada, pois as chamadas dos métodos são iguais, mudando apenas em funcionalidade. Assim, o controlador responsável pode trocar a visão para uma mais apropriada que consiga apresentar um conjunto de dados de maneira diferente.

O próximo componente da arquitetura MVC que foi implementado, foi o controlador. Esse conjunto de classes atua entregando para as visões os dados vindos do banco que foram solicitados pelos usuários, executando as operações necessárias para isso.

Como ocorreu no Modelo e na Visao, primeiro se pensou num componente estrutural que contivesse métodos comuns a todos os controladores. Isso possibilita continuar atuando com o mecanismo de herança através de uma classe abstrata que traz o que um controlador precisa para funcionar na aplicação. Na figura 26 é mostrada sua declaração.

Figura 26 - Classe Controlador

Fonte: autoria própria

A classe Controlador, diferente das demais, realiza uma herança dupla com duas classes do padrão Observador, uma para receber notificações das alterações do banco de dados e outra para interpretar os sinais que representam as ações do usuário ao interagir com os menus.

Os métodos definidos nessa classe são todos virtuais, o que a torna uma classe abstrata. Os controladores fazem herança com essa classe para terem acesso aos comportamentos de interpretar ações do usuário, inicializar os menus que devem controlar e receber notificações de mudança.

Os controladores também podem manter uma referência para o controlador que o chamou em algum momento. Essa característica é útil quando se deseja mudar de uma tela para outra em que é necessário alternar o controlador que está ativo no momento, pois apenas ele pode mostrar uma tela. Assim, quando for necessário voltar a visão anterior, basta trocar o controlador e redesenhar a tela.

Após a definição da classe Controlador, as demais estruturas do pacote de controladores foram codificadas. Cada controlador está relacionado com uma das visões de menus, com exceção da classe base.

O primeiro controlador implementado foi o ControladorDoMenuGeral. Na figura 27 é mostrada a definição da classe.

Fonte: autoria própria

A classe ControladorDoMenuGeral faz herança com Controlador para obter os métodos comuns aos controladores. Ela faz uso de referências para o MenuGeral, sua visão, a classe de serviços que faz acesso ao banco NotaService e a uma estrutura de decisão que permite selecionar um controlador para ser inicializado.

Os métodos, com exceção da validação de entradas, são todos sobrescritos da classe base Controlador. A validação acontece para evitar que o usuário informe dados incoerentes.

A classe ControladorDeDados possui as funções de iniciar o MenuDados e interpretar as entradas de dados do usuário para salvá-las na memória. Na figura 28 é mostrada a definição da classe.

Figura 28 - Classe ControladorDeDados

Fonte: autoria própria

Semelhante ao ControladorDoMenuGeral, essa classe faz herança pública com Controlador, estendendo seu comportamento. Também sobrescreve os métodos da classe base, implementando o comportamento apropriado.

O ControladorDeDados possui uma referência para sua visão, o MenuDados, uma outra para o serviço que manipula o banco e uma terceira para um novo serviço, responsável por preprocessar os dados antes de salvá-los no banco, para que nenhuma informação inconsistente seja salva e comprometa as operações. O ControladorDeOperacoes atua recebendo as operações informadas pelo usuário através do MenuOperacoes, interpretando e convocando o responsável por realizar a operação. Na figura 29 é mostrada a definição da classe.

Figura 29 - Classe ControladorDeOperacoes

implementa os seus métodos, sobrescrevendo-os. Também são usadas referências ao serviço que manipula o banco, ao MenuOperacoes e a um outro serviço, ProcessadorDeOperacoesService, responsável por processar as operações do usuário e devolver o resultado.

O ControladorDeResultados, gerencia o MenuResultados interpretando as ações do usuário e entregando a saída informada através do menu. Na figura 30 é mostrada a definição da classe.

Figura 30 - Classe ControladorDeResultados

Fonte: autoria própria

Da mesma forma que os demais controladores, a classe ControladorDeResultados faz uma herança pública com a classe base e sobrescreve seus métodos. Esse controlador possui, além das referências para seu menu e o serviço que manipula dados, uma referência para o serviço que gera os resultados desejados pelo usuário.

Os controladores implementados precisam usar outras classes para executar suas funções. Isso acontece porque os controladores não devem possuir lógica de negócios, servindo apenas como ponte entre as visões e os dados. Assim, para executar essas atividades lógicas, foi criada uma camada adicional a estrutura do MVC, uma camada de regras de negócio chamada de Serviço (Service). É nela em que todo o processamento pesado do software acontece. Como as funcionalidades dessa estrutura são muito variadas, não foi implementada uma classe base para realizar herança.

A classe NotaService define um conjunto de métodos que intermediam o acesso ao banco de dados virtual. Mesmo com a existência de NotaDAO, não é uma boa prática permitir manipulações diretas no banco, pois os dados enviados podem ser inválidos, o que gera inconsistência. A classe de serviços realiza validações dos dados de entrada, além de também ser responsável por notificar os controladores e visões de alterações que aconteceram no banco.

O banco virtual salva apenas uma entidade do tipo Nota por vez. Contudo, o C-Syncker manipula listas de Notas. Assim, para contornar isso, essa classe, em seu método de salvar, recebe uma lista de notas e atribui um identificador único a essas notas e depois salva cada item separadamente através de sucessivas chamadas ao banco. Quando o usuário precisa recuperar da memória uma lista, são buscadas todas as que possuem o mesmo identificador, retornando uma lista. Cada vez que um dado novo é escrito na memória, esse serviço recebe uma notificação e usa isso para disparar a própria notificação em cascata, mantendo os controladores, visões e outros serviços atualizados. Na figura 31 é mostrada a declaração da classe NotaService.

Figura 31 - Classe NotaService

Fonte: autoria própria

Na figura 31 são mostradas a referência para a classe que manipula o banco, a lista de observadores registrados, métodos para salvar dados, retornar valores do banco, verificar se uma determinada lista existe na memória e os responsáveis por registrar, atualizar e notificar observadores.

A classe ProcessadorDeDadosService é responsável por realizar conversões de dados dentro do programa. Ela transforma a entrada vinda do usuário em uma lista de notas que é salva na memória. Na figura 32 é mostrada a declaração da classe.

Fonte: autoria própria

O ProcessadorDeOperacoesService é a classe que tem a responsabilidade de manipular as operações que o C-Syncker pode realizar. Nela a operação escolhida pelo usuário é executada para os parâmetros informados na entrada. Na figura 33 é mostrada a declaração.

Figura 33 - Classe ProcessadorDeOperacoesService

Fonte: autoria própria

As classes de operações também são declaradas como serviços, já que são responsáveis por fazer processamento de dados. Essas classes são usadas por DecidaOperacao e ProcessadorDeOperacoesService para executar a operação informada pelo usuário. As figuras 34 e 35 mostram a declaração das operações de sincronização e desdobramento respectivamente.

Figura 34 - Classe da operação de sincronizar

Fonte: autoria própria

Figura 35 - Classe da operação de desdobrar

Fonte: autoria própria

As demais operações que são realizadas no programa seguem a mesma estrutura de declaração. A diferença está na forma de implementar o método executeOperacao, que recebe um parâmetro contendo as listas a serem processadas. Ele é sobrescrito por cada uma das operações, que definem suas lógicas de funcionamento.

ProcessadorDeResultadosService é a classe responsável por gerar as partituras no formato PDF e os arquivos de áudio para os resultados pré- composicionais obtidos. Na figura 36 é mostrada a declaração da classe.

Figura 36 - Classe ProcessadorDeResultadosService

os identificadores das listas que estão na memória e que serão transformadas em arquivos e o nome deles no sistema. Eles serão salvos dentro do diretório do C- Syncker.

3.4.3 Padrões de Projeto

3.4.3.1 O padrão Observador (Observer)

O padrão Observador foi implementado para desempenhar duas funções no programa. Primeiro para permitir que o banco de dados virtual notifique os seus observadores que seus dados mudaram. Segundo, para a criação de um sistema de eventos que permitiu interpretar as ações de um usuário.

A primeira interface do padrão Observador implementado foi uma classe de mesmo nome. Na figura 37 está a declaração da interface.

Figura 37 - Interface Observador

Fonte: autoria própria

Essa interface é herdada pelas classes Controlador e Visao como mostrado na figura 11. A classe Modelo possui uma lista de observadores registrados que serão atualizados através do método atualizeInscritos() quando os dados do banco forem modificados.

A segunda implementação do Observador foi na interface Evento. Como mostrado na figura 12, os controladores implementam a interface e as visões possuem a lista de observadores registrados. A figura 38 é mostrada a declaração da classe.

Figura 38 - Interface Evento

Evento define um método chamado identificadorDeEventos que recebe um parâmetro do tipo inteiro. Esse valor é referente a um código de evento, definido no “enum” apresentado na figura 20. Esses valores são enviados pelos menus aos seus controladores. Para cada código, uma ação diferente é tomada pelos controladores.

3.4.3.2 O padrão Estratégia (Strategy)

O padrão Estratégia foi usado para permitir um comportamento padronizado entre classes que pudesse ser reusado através de uma interface comum a todas. Em outras palavras, a Estratégia se torna uma aplicação do conceito de polimorfismo, em que um comportamento é especializado nas classes filhas e pode ser usado a partir da classe base.

Na versão atual do C-Syncker usou-se esse padrão em dois lugares que exigem capacidade de mudanças ou adição de novas classes sem ter que modificar muito o código. O primeiro uso foi na decisão de qual controlador deve ser usado para chamar um menu e o segundo para interpretar qual operação deve ser executada baseado na decisão do usuário.

A decisão de controlador é feita partir do ControladorDoMenuGeral, cuja principal funcionalidade é disparar o controlador referente ao menu que o usuário escolheu. Para isso, a classe faz uso de DecidaControlador.

Figura 39 - Classe que implementa a estratégia de decisão do Controlador

Fonte: autoria própria

Na figura 39 é mostrada a classe DecidaControlador, que implementa a estratégia de decisão. O método retorneControlador recebe como entrada o tipo de menu que se deseja mostrar na tela e uma referência para o serviço que manipula o banco e decide qual o controlador será retornado.

A segunda aplicação do padrão Estratégia está na decisão da operação que será executada pelo ProcessadorDeOperacoesService. Seguindo a mesma estrutura da implementação anterior, uma classe base Operacao foi definida e todas as operações fazem herança com ela. Na figura 13 é mostrada a hierarquia. Para realizar a decisão, foi implementada a classe DecidaOperacao, que aplica o mesmo princípio de DecidaControlador. Na figura 40 é mostrada a definição da classe.

Fonte: autoria própria

Na classe mostrada na figura 40, o método decidaOperacao também possui uma referência para o serviço que acessa o banco e uma entrada. A entrada define qual operação será realizada e quais são os parâmetros da operação, ou seja, quais listas serão usadas. O retorno é de uma referência para a classe base que aponta para a operação a ser realizada, fazendo uso do polimorfismo.

Em uma análise geral, o que os métodos retorneControlador e decidaOperacao fazem é concentrar as tomadas de decisão em um único lugar, permitindo assim que, quando for necessário criar um novo tipo de controlador ou uma nova operação, seja necessário alterar apenas nessas estruturas para integrar ao sistema. Isso facilita a manutenção e desenvolvimento de novas funcionalidades ao sistema, causando impacto mínimo na aplicação que já está funcional.

3.4.3.3 O padrão Composto (Composite)

O padrão Composto foi usado na construção dos menus, já que eles são estruturas que podem conter outros menus dentro deles (estrutura parte-todo). A figura 18 é mostrada a implementação da classe base Menu.

A classe base apresenta um atributo que é uma lista de menu. Essa lista de menus é uma composição e permite que submenus existam dentro de seus menus

Dans le document Program Product (Page 25-29)