Difference between revisions of "Programação com Objectos/Projecto de Programação com Objectos/Enunciado do Projecto de 2024-2025 (rascunho)"

From Wiki**3

< Programação com Objectos‎ | Projecto de Programação com Objectos
(Calcular Satisfação)
 
(39 intermediate revisions by the same user not shown)
Line 1: Line 1:
{{PRJPOAvisosEN20242025}}
+
#REDIRECT [[Programação com Objectos/Projecto de Programação com Objectos/Enunciado do Projecto de 2024-2025]]
{{PRJPOMandatory20242025}}
 
{{TOCright}}
 
'''<font color="red">EM PREPARAÇÃO</font>'''
 
 
 
'''<font color="red">ÉPOCA NORMAL</font>'''
 
 
 
O objectivo do projecto é desenvolver uma aplicação de gestão de um hotel veterinário que dispõe de tratadores, veterinários e habitats com árvores.
 
 
 
= Propriedades e funcionalidade =
 
 
 
Os animais de várias espécies são mantidos por tratadores que são responsáveis por distribuir a comida e pela limpeza dos habitats, e por veterinários, que têm a responsabilidade de zelar pela saúde dos animais. Quando um animal recebe uma vacina não apropriada à sua espécie, por causa de um erro veterinário, por exemplo, fica com a saúde afectada até ao fim da sua vida. Os habitats têm árvores. É possível calcular o grau de satisfação dos animais e dos funcionários.
 
 
 
Em todos os campos identificadores ou nomes, excepto se indicado o contrário, as diferenças entre maiúsculas e minúsculas são irrelevantes.
 
 
 
== Espécies ==
 
 
 
As espécies são identificadas por uma chave única (cadeia de caracteres arbitrária definida na altura da criação).
 
 
 
Cada espécie tem um nome (cadeia de caracteres única, i.e., não existem duas espécies distintas com o mesmo nome) e um registo dos animais da espécie.
 
 
 
== Animais ==
 
 
 
Os animais são identificados por uma chave única (cadeia de caracteres arbitrária definida na altura da criação).
 
 
 
Cada animal tem um nome (cadeia de caracteres não única) e informação acerca da sua espécie e do estado de saúde.
 
 
 
É possível calcular o nível de satisfação de um animal. Este valor depende de vários factores (ver a seguir).
 
 
 
=== Satisfação dos Animais ===
 
 
 
A satisfação dos animais é afectada positivamente quando existem mais animais da mesma espécie no mesmo habitat e afectada negativamente quando existem animais de outras espécies. O número total de animais no habitat e o próprio habitat também influenciam a satisfação dos animais que lá vivem.
 
 
 
A satisfação de um animal '''a''' no seu habitat '''h''' é calculada pela fórmula:
 
 
 
* '''satisfação(a) = 20 + 3 * iguais(a, h) - 2 * diferentes(a, h) + área(h) / população(h) + adequação(a, h)'''
 
 
 
Nesta equação, '''iguais''' conta o número de animais da mesma espécie no habitat (sem contar com '''a'''), '''diferentes''' é o número de animais de espécies diferentes da de '''a''' no habitat, '''área''' é a área do habitat e '''população''' é a população total do habitat, '''adequação''' é '''20''' se a influência do habitat for positiva, '''-20''' se for negativa e '''0''' se a influência for neutra (condição por omissão).
 
 
 
== Habitats ==
 
 
 
Os habitats são identificados por uma chave única (cadeia de caracteres arbitrária definida na altura da criação).
 
 
 
Cada habitat tem um nome (cadeia de caracteres; não única) e informação sobre a área (número inteiro). Os habitats estão associados a zero ou mais árvores e a zero ou mais animais. Estão ainda associados às espécies cuja satisfação influenciam.
 
 
 
Os habitats podem ser mais (ou menos) adequados para determinadas espécies. A adequação tem impacto no grau de satisfação dos animais. Por omissão, um habitat tem um impacto neutro para cada espécie. <!--Mas um habitat pode ser mais adequado a um determinado conjunto de espécies e/ou menos adequado a outro subconjunto de espécies.-->
 
 
 
== Árvores ==
 
 
 
As árvores são identificadas por uma chave única (cadeia de caracteres arbitrária definida na altura da criação). Cada árvore tem ainda nome (cadeia de caracteres; não única) e idade em anos (número inteiro). As árvores podem ser de folha caduca ou perene e são caracterizadas pela dificuldade de limpeza (número inteiro) que induzem no habitat onde estão implantadas (definido no momento da introdução da árvore no habitat).
 
 
 
A vida das árvores segue o ciclo definido pelas estações do ano. Assim, por exemplo, as árvores de folha caduca perdem as folhas principalmente durante o Outono, ficando
 
sem folhas no Inverno. As árvores de folha perene perdem algumas folhas durante todas as estações, mas mais durante o Inverno.
 
 
 
O esforço de limpeza de uma árvore é assim determinado pelo produto de três factores: o primeiro corresponde à dificuldade intrínseca de limpeza da árvore; o segundo depende da estação do ano e do tipo de árvore, tal como indicado na tabela seguinte (função '''esforço_sazonal'''); e o terceiro corresponde a um factor que aumenta com a idade da árvore (ver abaixo).
 
 
 
{|
 
! style="background: #ebebeb;" | '''Estação »'''
 
! style="background: #ebebeb; text-align: center; font-weight: normal;" | Inverno
 
! style="background: #ebebeb; text-align: center; font-weight: normal;" | Primavera
 
! style="background: #ebebeb; text-align: center; font-weight: normal;" | Verão
 
! style="background: #ebebeb; text-align: center; font-weight: normal;" | Outono
 
|-
 
| '''Folha caduca »'''
 
! style="text-align: center; font-weight: normal;" | 0
 
! style="text-align: center; font-weight: normal;" | 1
 
! style="text-align: center; font-weight: normal;" | 2
 
! style="text-align: center; font-weight: normal;" | 5
 
|-
 
| '''Folha perene »'''
 
! style="text-align: center; font-weight: normal;" | 2
 
! style="text-align: center; font-weight: normal;" | 1
 
! style="text-align: center; font-weight: normal;" | 1
 
! style="text-align: center; font-weight: normal;" | 1
 
|}
 
 
 
O esforço de limpeza proporcional à idade da árvore cresce logaritmicamente (i.e., não muito rapidamente): '''log(idade + 1)''' (logaritmo natural).
 
 
 
Combinando os vários elementos, obtém-se a fórmula:
 
* '''esforço_limpeza(a) = dificuldade_limpeza(a) * esforço_sazonal(a) * log(idade(a) + 1)'''
 
 
 
Quando uma árvore é criada, fica na estação do ano em que a aplicação estiver no momento da criação. A estação inicial da aplicação é a '''Primavera'''.
 
 
 
As árvores envelhecem com as estações, i.e., a idade aumenta em 1 unidade (1 ano) a cada 4 estações (note-se que o incremento não é necessariamente simultâneo em todas as árvores).
 
 
 
== Funcionários ==
 
 
 
Os funcionários são identificados por uma chave única (cadeia de caracteres arbitrária definida na altura da criação). Os funcionários têm um nome (cadeia de caracteres não única).
 
 
 
Existem dois tipos de funcionários: tratadores e veterinários. Cada tratador está associado aos habitats da sua responsabilidade (zero ou mais). Cada veterinário está associado às espécies que sabe vacinar (zero ou mais).
 
 
 
=== Satisfação dos Veterinários ===
 
A satisfação dos veterinários é afectada positivamente pela existência de outros veterinários com a mesma responsabilidade ('''n_veterinários(e)''') e negativamente pelo número de animais que estão sob a sua responsabilidade. Apenas se contabilizam as espécies que o veterinário pode tratar ('''espécies(v)''').
 
 
 
A satisfação para um veterinário '''v''' é calculada pela fórmula:
 
* '''satisfação(v) = 20 - trabalho(v)'''
 
* '''trabalho(v) = Σ (população(e) / n_veterinários(e)), e ∈ espécies(v)'''
 
 
 
=== Satisfação dos Tratadores ===
 
A satisfação dos tratadores é afectada negativamente pelo trabalho que lhes é atribuído. Apenas se contabilizam os habitats sob responsabilidade do tratador ('''habitats(t)'''). O trabalho é também influenciado pelas árvores existentes no habitat ('''árvores(h)''') (ver também secção sobre habitats e árvores).
 
 
 
A satisfação para um tratador '''t''' é calculada pela fórmula:
 
* '''satisfação(t) = 300 - trabalho(t)'''
 
* '''trabalho(t) = Σ (trabalho_no_habitat(h) / número_de_tratadores_podem_cuidar_habitat(h)), h ∈ habitats(t)'''
 
* '''trabalho_no_habitat(h) = área(h) + 3 * população(h) + Σ esforço_limpeza(a), a ∈ árvores(h)'''
 
 
 
== Vacinas ==
 
 
 
As vacinas são identificadas por uma chave única (cadeia de caracteres arbitrária definida na altura da criação).
 
 
 
Cada vacina tem um nome (cadeia de caracteres; não única) e está associada às espécies a que pode ser aplicada. Tem ainda o registo de aplicações a cada animal pelos veterinários, por ordem de vacinação.
 
 
 
=== Problemas associados à vacinação ===
 
 
 
O estado de saúde de um animal é o histórico de eventos (inicialmente vazio), relacionados com a vacinação do animal, a partir da situação inicial, entre os quais estão os danos causados por más vacinações.
 
 
 
Se a espécie do animal está incluída nas espécies para as quais uma vacina é apropriada, então o valor do dano causado pela vacina é 0 (zero):
 
* '''dano(v, a) = 0'''
 
 
 
Caso contrário, os danos causados pela má administração de uma vacina '''v''' a um animal '''a''' dependem do máximo do número de letras distintas entre o nome da espécie de '''a''' ('''espécie(a)''') e os nomes das espécies a que se destinava '''v''' ('''espécies(v)'''). <!--Considera-se que os nomes '''aab''' e '''ba''' têm apenas 1 carácter distinto, sendo a ordem irrelevante:-->
 
* '''dano(v, a) = MAX (tamanho_nomes(espécie(a), e) - caracteres_comuns(espécie(a), e)), e ∈ espécies(v)'''
 
* '''tamanho_nomes(espécie1, espécie2) = max(tamanho(espécie1), tamanho(espécie2))'''
 
 
 
Por exemplo, quando uma ave recebe uma vacina destinada apenas a um mamífero, o dano resultante da má aplicação da vacina é igual a 6.
 
 
 
A seguinte tabela descreve os resultados associados aos potenciais danos causados por vacinações:
 
{|
 
! style="background: #ebebeb;" | '''Dano'''
 
! style="background: #ebebeb;" | '''Termo a adicionar na apresentação do estado de saúde'''
 
|-
 
| 0 (mesma espécie)
 
| NORMAL
 
|-
 
| 0 (espécies diferentes)
 
| CONFUSÃO
 
|-
 
| 1 a 4
 
| ACIDENTE
 
|-
 
| 5 ou mais
 
| ERRO
 
|}
 
 
 
Por exemplo, um animal que tenha recebido 2 vacinas com um dano entre 1 e 4 (ACIDENTE), três vacinas com um dano igual ou superior a 5 (ERRO) e uma vacina correctamente aplicada, apresenta o seguinte historial de saúde (usa-se a vírgula como separador): ACIDENTE,ACIDENTE,ERRO,ERRO,ERRO,NORMAL (i.e., concatenação ordenada por ordem de ocorrência).
 
 
 
= Funcionalidade da aplicação =
 
 
 
A aplicação permite:
 
* Gerir toda a informação relativa aos conceitos acima;
 
* Preservar persistentemente o seu estado (não é possível manter várias versões do estado da aplicação em simultâneo);
 
* Calcular o estado de satisfação dos animais e funcionários;
 
* Calcular a satisfação global (i.e., somatório da satisfação de todos os animais e funcionários);
 
* Efectuar pesquisas sujeitas a vários critérios e sobre as diferentes entidades geridas.
 
 
 
Uma base de dados textual com conceitos pré-definidos pode ser [[#Inicialização por Ficheiro de Dados Textuais|carregada no início da aplicação]].
 
 
 
{{CVSCode|Note-se que não é necessário nem desejável implementar de raiz a aplicação: já existem classes que representam e definem a interface geral da funcionalidade do ''core'' da aplicação, tal como é visível pelos comandos da aplicação.}}
 
{{CVSCode|A interface geral do ''core'' já está parcialmente implementada na classe '''hva.HotelManager''' e outras fornecidas (cujos nomes devem ser mantidos), devendo ser adaptadas onde necessário. É ainda necessário criar e implementar as restantes classes que suportam a operação da aplicação.}}
 
 
 
== Operações sobre animais ==
 
As operações são as seguintes: (i) [[#Visualizar todos os animais|visualizar todos os animais]]; (ii) [[#Registar um novo animal|registar um novo animal]]; (iii) [[#Transferir um animal para um habitat|transferir um animal para um habitat]]; (iv) [[#Calcular a satisfação de um animal|calcular a satisfação de um animal]].
 
 
 
== Operações sobre funcionários ==
 
As operações são as seguintes: (i) visualizar um funcionário; (ii) registar um novo funcionário; (iii) atribuir uma nova responsabilidade a um funcionário; (iv) retirar uma responsabilidade a um funcionário; (v) calcular a satisfação de um funcionário.
 
 
 
== Operações sobre habitats e árvores ==
 
As operações são as seguintes: (i) visualizar um habitat; (ii) registar um novo habitat; (iii) alterar a área de um habitat; (iv) associar a um habitat as espécies que aumentam/diminuem a sua satisfação por residir nele; (v) plantar uma árvore; (vi) provocar uma alteração no ciclo biológico de uma árvore.
 
 
 
== Operações sobre vacinas e vacinações ==
 
As operações são as seguintes: (i) visualizar uma vacina; (ii) registar uma nova vacina; (iii) ministrar uma vacina a um animal; (iv) consultar o histórico de vacinação de uma dada vacina.
 
 
 
== Pesquisas ==
 
 
 
É possível efectuar pesquisas sob vários critérios e sobre as diversas entidades: (i) animais que residem num determinado habitat; (ii) animais que tomaram uma determinada vacina; (iii) vacinas que foram dadas a um determinado animal; (iv) habitats da responsabilidade de um tratador; (v) árvores que pertencem a um determinado habitat.
 
 
 
== Serialização ==
 
 
 
É possível guardar e recuperar o estado actual da aplicação, preservando toda a informação relevante (descrita acima).
 
 
 
= Requisitos de desenho =
 
 
 
A aplicação a desenvolver deve seguir o princípio de desenho aberto-fechado por forma a aumentar a extensibilidade do seu código. Por exemplo, deve ser possível adicionar novos tipos de funcionários com um impacto mínimo no código já existente do domínio.
 
 
 
Aplicação de um padrão de desenho para melhorar a legibilidade do código relacionado com o conceito árvore e permitir ao mesmo tempo que se possam adicionar novos eventos relacionados com as estações sem que isso implique alterar o código relacionado com árvores. O padrão deve ainda poder suportar novas funcionalidades dependentes da estação actual (por exemplo, qual a cor das folhas de uma árvore, que vai depender do tipo de árvore e da estação actual) sem comprometer a legibilidade da solução.
 
 
 
Aplicação de um padrão de desenho que permita novas políticas de cálculo da satisfação dos funcionários sem impacto no código existente. A solução concretizada deve permitir alterar o cálculo da satisfação de um funcionário em tempo de execução. Quando é criado um funcionário, o cálculo da satisfação segue a fórmula descrita neste enunciado.
 
<!--
 
Do ponto de vista do desenho do domínio da aplicação a realizar para a primeira entrega do projecto não é necessário ter em conta estes dois requisitos. Estes dois requisitos apenas precisam de ser considerados na entrega final do projecto.
 
-->
 
<!--
 
Devem ser possíveis extensões ou alterações de funcionalidade com impacto mínimo no código produzido: em particular, deve ser simples definir novos tipos de problemas decorrentes da aplicação incorrecta de vacinas. A definição de árvores com novos estados e diferentes formas de estimar a sua evolução; e novas políticas de cálculo da satisfação dos funcionários e animais.
 
-->
 
 
 
Deve ser possível introduzir novos métodos de pesquisa com um impacto mínimo na implementação desenvolvida.
 
 
 
Apesar de haver na especificação actual apenas um hotel, o código não deve assumir que não podem existir mais instâncias.
 
 
 
= Interacção com o utilizador =
 
 
 
Descreve-se nesta secção a '''funcionalidade máxima''' da interface com o utilizador. Em geral, os comandos pedem toda a informação antes de procederem à sua validação (excepto onde indicado). Todos os menus têm automaticamente a opção '''Sair''' (fecha o menu).
 
 
 
As operações de pedido e apresentação de informação ao utilizador '''devem''' realizar-se através dos objectos ''form'' e ''display'', respectivamente, presentes em cada comando. As mensagens são produzidas pelos métodos das [[Programação com Objectos/Projecto de Programação com Objectos/Material de Apoio ao Desenvolvimento|bibliotecas de suporte]] ('''po-uilib''' e '''hva-app'''). As mensagens não podem ser usadas no núcleo da aplicação ('''hva-core'''). Além disso, não podem ser definidas novas. Potenciais omissões devem ser esclarecidas antes de qualquer implementação.
 
 
 
A apresentação de listas (e.g., animais, funcionários, vacinas, etc.) faz-se por ordem crescente da respectiva chave, excepto em caso de indicação em contrário. A ordem das chaves alfanuméricas deve ser lexicográfica (UTF-8), não havendo distinção entre maiúsculas e minúsculas.
 
 
 
De um modo geral, sempre que no contexto de uma operação com o utilizador aconteça alguma excepção, então a operação não deve ter qualquer efeito no estado da aplicação, excepto se indicado em contrário na operação em causa. As excepções estão na package '''hva.app.exceptions''', excepto se houver indicação contrária.
 
 
 
As excepções usadas na interacção (subclasses de '''pt.tecnico.uilib.menus.CommandException'''), excepto se indicado, são lançadas pelos comandos (subclasses de '''pt.tecnico.uilib.menus.Command''') e tratadas pelos menus (instâncias de subclasses de '''pt.tecnico.uilib.menus.Menu'''). Outras excepções não devem substituir as fornecidas nos casos descritos.
 
 
 
Nos pedidos e usos dos vários identificadores, podem ocorrer as seguintes excepções, caso o identificador indicado não corresponda a um objecto conhecido (excepto no processo de registo ou caso indicação em contrário). Note-se que estas excepções não são utilizáveis no núcleo da aplicação.
 
{|
 
! style="background: #ebebeb;" | '''Tipo de dados'''
 
! style="background: #ebebeb;" | '''Classe'''
 
! style="background: #ebebeb;" | '''Pedido a apresentar'''
 
! style="background: #ebebeb;" | '''Excepção a lançar se desconhecido'''
 
|-
 
| Animal
 
| '''Animal'''
 
| '''hva.app.animal.Prompt.animalKey()'''
 
| '''hva.app.exceptions.UnknownAnimalKeyException'''
 
|-
 
| Espécie 
 
| '''Species'''
 
| '''hva.app.animal.Prompt.speciesKey()'''
 
| '''hva.app.exceptions.UnknownSpeciesKeyException'''
 
|-
 
| Funcionário
 
| '''Employee'''
 
| '''hva.app.employee.Prompt.employeeKey()'''
 
| '''hva.app.exceptions.UnknownEmployeeKeyException'''
 
|-
 
| Habitat
 
| '''Habitat'''
 
| '''hva.app.habitat.Prompt.habitatKey()'''
 
| '''hva.app.exceptions.UnknownHabitatKeyException'''
 
|-
 
| Árvore
 
| '''Tree'''
 
| '''hva.app.habitat.Prompt.treeKey()'''
 
| '''hva.app.exceptions.UnknownTreeKeyException'''
 
|-
 
| Vacina
 
| '''Vaccine'''
 
| '''hva.app.vaccine.Prompt.vaccineKey()'''
 
| '''hva.app.exceptions.UnknownVaccineKeyException'''
 
|}
 
 
 
Alguns casos particulares podem usar pedidos específicos não apresentados nesta tabela.
 
<!--
 
* Sempre que for pedido o identificador de um animal ('''Prompt.animalKey()''') (cadeia de caracteres) e o identificador não existir, deve ser lançada a excepção '''hva.app.exceptions.UnknownAnimalKeyException''' (excepto no processo de registo ou caso indicação em contrário).
 
* Sempre que for pedido o identificador de uma espécie ('''Prompt.speciesKey()''') (cadeia de caracteres) e o identificador não existir, deve ser lançada a excepção '''hva.app.animal.UnknownSpeciesKeyException''' (excepto no processo de registo ou caso indicação em contrário).
 
* Sempre que for pedido o identificador de um funcionário ('''Prompt.employeeKey()''') e o identificador não existir, deve ser lançada a excepção '''UnknownEmployeeKeyException''' (excepto no processo de registo ou caso indicação em contrário).
 
* Sempre que for pedido o identificador de um habitat ('''Prompt.habitatKey()''') e o identificador não existir, deve ser lançada a excepção '''UnknownHabitatKeyException''' (excepto no processo de registo ou caso indicação em contrário).
 
* Sempre que for pedido o identificador de uma árvore ('''Prompt.treeKey()''') e o identificador não existir, deve ser lançada a excepção '''UnknownTreeKeyException''' (excepto no processo de registo ou caso indicação em contrário).
 
* Sempre que for pedido o identificador de uma vacina ('''Prompt.vaccineKey()''') e o identificador não existir, deve ser lançada a excepção '''UnknownVaccineKeyException''' (excepto no processo de registo ou caso indicação em contrário).
 
-->
 
{{CVSCode|Note-se que o programa principal e os comandos e menus, a seguir descritos, já estão parcialmente implementados nas ''packages'' '''hva.app''', '''hva.app.main''', '''hva.app.edit''', '''hva.app.search'''. Estas classes são de uso obrigatório e estão disponíveis no [[Programação com Objectos/Projecto de Programação com Objectos/Repositório GIT|GIT]] (módulo '''hva-app''').}}
 
 
 
== Menu Principal ==
 
As acções deste menu permitem gerir a salvaguarda do estado da aplicação, abrir submenus e aceder a alguma informação global. A lista completa é a seguinte: [[#Salvaguarda do estado actual da aplicação|Criar]], [[#Salvaguarda do estado actual da aplicação|Abrir]], [[#Salvaguarda do estado actual da aplicação|Guardar]], [[#Avançar Estação do Ano|Avançar Estação do Ano]], [[#Ver Estado de Satisfação|Ver Estado de Satisfação]], [[#Menu de Gestão de Animais|Gestão de Animais]], [[#Menu de Gestão de Funcionários|Gestão de Funcionários]], [[#Menu de Gestão de Vacinas|Gestão de Vacinas]], [[#Menu de Gestão de Habitats|Gestão de Habitats]] e [[#Menu de Consultas|Consultas]]. As secções abaixo descrevem pormenorizadamente as acções associadas a estas opções.
 
 
 
{{CVSCode|As etiquetas das opções deste menu estão definidas na classe '''hva.app.main.Label'''. Todos os métodos correspondentes às mensagens de diálogo para este menu estão definidos em  '''hva.app.main.Prompt''' e '''hva.app.main.Message'''.}}
 
{{CVSCode|Estes comandos já estão implementados nas classes da ''package'' '''hva.app.main''' (disponível no GIT), respectivamente: '''DoNewFile''', '''DoOpenFile''', '''DoSaveFile''', '''DoAdvanceSeason''', '''DoShowGlobalSatisfaction''', '''DoOpenAnimalsMenu''', '''DoOpenEmployeesMenu''', '''DoOpenHabitatsMenu''', '''DoOpenVaccinesMenu''', '''DoOpenLookupsMenu'''.}}
 
 
 
=== Salvaguarda do estado actual da aplicação ===
 
 
 
Inicialmente, a aplicação não tem qualquer informação, excepto quando usada a propriedade '''import''' (ver abaixo) para pré-carregar dados iniciais. <!-- Na situação em que a aplicação começa sem importação de dados, apenas são apresentadas as opções Criar e Abrir, pois as restantes necessitam da existência de informação do domínio. As opções irrelevantes nesta situação devem ser omitidas.-->
 
O conteúdo da aplicação (toda a informação actualmente em memória) pode ser guardado para posterior recuperação (via serialização Java: '''java.io.Serializable'''). Na leitura e escrita do estado da aplicação, devem ser tratadas as excepções associadas. A funcionalidade é a seguinte:
 
 
 
* '''Criar''' -- Cria uma nova aplicação vazia: a aplicação não fica associada a nenhum ficheiro (é anónima).
 
* '''Abrir''' -- Carrega os dados de uma sessão anterior a partir de um ficheiro previamente guardado (ficando este ficheiro associado à aplicação, para futuras operações de salvaguarda). Pede-se o nome do ficheiro a abrir ('''Prompt.openFile()'''). Caso ocorra um problema na abertura ou processamento do ficheiro, deve ser lançada a excepção '''FileOpenFailedException'''. A execução bem-sucedida desta opção substitui toda a informação da aplicação.
 
* '''Guardar''' -- Guarda o estado actual da aplicação no ficheiro associado. Se não existir associação, pede-se o nome do ficheiro a utilizar, ficando a ele associado (para operações de salvaguarda subsequemtes). Esta interacção realiza-se através do método '''Prompt.newSaveAs()'''. Não é executada nenhuma acção se não existirem alterações desde a última salvaguarda.
 
 
 
<!--Apenas existe um hotel na aplicação. -->
 
Quando se abandona uma aplicação com modificações não guardadas (porque se cria ou abre outra), deve perguntar-se se se quer guardar a informação actual antes de a abandonar, através de '''Prompt.saveBeforeExit()''' (a resposta é obtida invocando '''readBoolean()''' ou de '''Form.confirm()''').
 
 
 
{{Suggestion|Note-se que a opção '''Abrir''' não permite a leitura de ficheiros de texto (estes apenas podem ser utilizados no início da aplicação).}}
 
{{Suggestion|A opção '''Sair''' nunca implica a salvaguarda do estado da aplicação, mesmo que existam alterações.}}
 
 
 
== Avançar Estação do Ano ==
 
Esta opção permite avançar a estação do ano, afectando todas as árvores em todos os habitats.
 
 
 
O comando deve apresentar na saída o código para a estação actual: '''0''' para Primavera, '''1''' para Verão, '''2''' para Outono e '''3''' para Inverno.
 
 
 
== Ver Estado de Satisfação Global ==
 
 
 
O sistema apresenta, de imediato, o somatório dos estados de satisfação de todas as entidades registadas no hotel: animais e funcionários.
 
 
 
Note-se que o valor a apresentar é o que resulta do arredondamento ao inteiro mais próximo (via '''Math.round''').
 
 
 
== Menu de Gestão de Animais ==
 
 
 
Este menu permite operar sobre animais. A lista completa é a seguinte: (i) [[#Visualizar todos os animais|visualizar todos os animais]]; (ii) [[#Registar um novo animal|registar um novo animal]]; (iii) [[#Transferir um animal para um habitat|transferir um animal para um habitat]]; (iv) [[#Calcular a satisfação de um animal|calcular a satisfação de um animal]]. As secções abaixo descrevem estas opções.
 
 
 
{{CVSCode|As etiquetas das opções deste menu estão definidas em '''hva.app.animal.Label'''. Os métodos correspondentes às mensagens de diálogo para este menu estão definidos em  '''hva.app.animal.Prompt''' e '''hva.app.animal.Message'''.}}
 
{{CVSCode|Estes comandos já estão implementados nas classes da ''package'' '''hva.app.animal''' (disponível no GIT), respectivamente: '''DoShowAllAnimals''', '''DoRegisterAnimal''', '''DoTransferToHabitat''', '''DoShowSatisfactionOfAnimal'''.}}
 
 
 
=== Visualizar todos os animais ===
 
 
 
O formato de apresentação de cada animal é o seguinte:
 
<source lang="text">
 
 ANIMAL|idAnimal|nomeAnimal|idEspécie|historialDeSaúde|idHabitat
 
</source>
 
 
 
Se o animal nunca foi vacinado (com ou sem sucesso), o historial de saúde deve ser apresentado como '''VOID''':
 
<source lang="text">
 
 ANIMAL|idAnimal|nomeAnimal|idEspécie|VOID|idHabitat
 
</source>
 
 
 
O historial de saúde é apresentado como descrito em [[#Problemas associados à vacinação|Problemas associados à vacinação]], i.e., uma sequência de eventos separados por vírgulas.
 
 
 
=== Registar um novo animal ===
 
 
 
O sistema pede o identificador do novo animal. De seguida pede o nome do animal ('''Prompt.animalName()'''), o identificador da espécie e o identificador do habitat.
 
 
 
Se o identificador da espécie não existe, deve pedir-se o nome da nova espécie ('''Prompt.speciesName()''') (cadeia de caracteres) e registá-la com o identificador indicado.
 
 
 
Se o identificador do animal já existir, lança a excepção '''DuplicateAnimalKeyException''', não se processando o registo.
 
 
 
=== Transferir um animal para um habitat ===
 
 
 
Para realizar a operação, o sistema pede o identificador do animal e o identificador do habitat de destino.<!-- Em caso de erro, o habitat não é alterado.-->
 
 
 
=== Calcular a satisfação de um animal ===
 
 
 
O sistema pede o identificador do animal, sendo apresentado o valor da sua satisfação (arredondado ao inteiro mais próximo via '''Math.round''').
 
 
 
== Menu de Gestão de Funcionários ==
 
 
 
Este menu permite operar sobre funcionários. A lista completa é a seguinte: [[#Visualizar|Visualizar]], [[#Registar|Registar]], [[#Atribuir Responsabilidade|Atribuir Responsabilidade]], [[#Retirar Responsabilidade|Retirar Responsabilidade]], [[#Calcular Satisfação|Calcular Satisfação]]. As secções abaixo descrevem estas opções.
 
 
 
{{CVSCode|As etiquetas das opções deste menu estão definidas na classe '''hva.app.employee.Label'''. Todos os métodos correspondentes às mensagens de diálogo para este menu estão definidos em '''hva.app.employee.Prompt''' e '''hva.app.employee.Message'''.}}
 
{{CVSCode|Estes comandos já estão implementados nas classes da ''package'' '''hva.app.employee''' (disponível no GIT), respectivamente: '''DoShowAllEmployees''', '''DoRegisterEmployee''', '''DoAddResponsibility''', '''DoRemoveResponsibility''', '''DoShowSatisfactionOfEmployee'''.}}
 
 
 
=== Visualizar todos os funcionários ===
 
 
 
O formato de apresentação de cada funcionário é o seguinte:
 
<source lang="text">
 
 tipo|id|nome|idResponsabilidades
 
</source>
 
 
 
Os valores para o campo ''tipo'' são '''VET''' ou '''TRT'''.
 
Os valores para o campo ''idResponsabilidades'' são os identificadores, separados por vírgulas, dos habitats que um tratador pode limpar ou das espécies de animais que um veterinário pode tratar.
 
 
 
Se o funcionário não tiver responsabilidades atribuídas, o formato de apresentação é o seguinte:
 
<source lang="text">
 
 tipo|id|nome
 
</source>
 
 
 
=== Registar um novo funcionário ===
 
 
 
O sistema pede o identificador do novo funcionário, assim como o seu nome ('''Prompt.employeeName()''') (cadeia de caracteres). De seguida, pede-se o tipo de funcionário ('''Prompt.employeeType()'''). A resposta deve ser '''VET''' (é registado um veterinário) ou '''TRT''' (é registado um tratador). Se a resposta não corresponder a nenhum dos dois valores, a pergunta é repetida até se obter uma resposta válida. Quando um funcionário é registado fica sem qualquer responsabilidade.
 
 
 
Se já existir um funcionário com o mesmo identificador, deve ser lançada a excepção '''DuplicateEmployeeKeyException''', não se realizando qualquer acção.
 
 
 
=== Atribuir uma nova responsabilidade a um funcionário ===
 
 
 
O sistema pede o identificador do funcionário e o identificador da nova responsabilidade ('''Prompt.responsibilityKey()'''): o identificador de uma espécie, se for um veterinário; ou o identificador de um habitat, se for um tratador.
 
 
 
Se o funcionário já tinha essa responsabilidade, não é executada nenhuma acção.
 
 
 
Se a responsabilidade não existir, então deve ser lançada a excepção '''NoResponsibilityException'''.
 
 
 
=== Retirar uma responsabilidade a um funcionário ===
 
 
 
O sistema pede o identificador do funcionário e o identificador da responsabilidade a retirar ('''Prompt.responsibilityKey()'''): o identificador de uma espécie, se for um veterinário; ou o identificador de um habitat, se for um tratador. Se a responsabilidade não estava atribuída ao funcionário ou não existe, é lançada a excepção '''NoResponsabilityException'''.
 
 
 
=== Calcular a satisfação de um funcionário ===
 
 
 
O sistema pede o identificador do funcionário, sendo apresentado o valor da sua satisfação (arredondado ao inteiro mais próximo via '''Math.round''').
 
 
 
== Menu de Gestão de Habitats ==
 
 
 
Este menu permite operar sobre habitats. A lista completa é a seguinte: [[#Visualizar|Visualizar]], [[#Registar|Registar]], [[#Alterar área|Alterar área]], [[#Alterar influência em espécie|Alterar influência em espécie]], [[#Plantar árvore|Plantar árvore]] e [[#Consultar Árvores de um Habitat|Consultar Árvores de um Habitat]]. As secções abaixo descrevem estas opções.
 
 
 
{{CVSCode|As etiquetas das opções deste menu estão definidas na classe '''hva.app.habitat.Label'''. Todos os métodos correspondentes às mensagens de diálogo para este menu estão definidos em '''hva.app.habitat.Prompt''' e '''hva.app.habitat.Message'''.}}
 
{{CVSCode|Estes comandos já estão implementados nas classes da ''package'' '''hva.app.habitat''' (disponível no GIT), respectivamente: '''DoShowAllHabitats''', '''DoRegisterHabitat''', '''DoChangeHabitatArea''', '''DoChangeHabitatInfluence''', '''DoAddTreeToHabitat''', '''DoShowAllTreesInHabitat'''.}}
 
 
 
=== Visualizar ===
 
Esta opção permite visualizar todos os habitats.
 
 
 
O formato de apresentação para cada habitat é o seguinte:
 
<source lang="text">
 
 HABITAT|idHabitat|nome|área|númeroÁrvores
 
</source>
 
 
 
Esta linha inicial pode ser seguida de zero ou mais linhas, cada uma com a descrição de cada árvore pertencente ao habitat usando o seguinte formato:
 
<source lang="text">
 
 ÁRVORE|idÁrvore|nomeÁrvore|idadeÁrvore|dificuldadeLimpeza|tipoÁrvore|cicloBiológico
 
</source>
 
 
 
O valor de '''dificuldadeLimpeza''' é arredondado ao inteiro mais próximo (via '''Math.round''').
 
 
 
O valores possíveis para ''tipoÁrvore'' são '''PERENE''' e '''CADUCA'''.
 
 
 
Os possíveis valores para o campo '''cicloBiológico''' são:
 
 
 
{|
 
| Tipo de Árvore
 
| Inverno
 
| Primavera
 
| Verão
 
| Outono
 
|-
 
| CADUCA
 
| SEMFOLHAS
 
| GERARFOLHAS
 
| COMFOLHAS
 
| LARGARFOLHAS
 
|-
 
| PERENE
 
| LARGARFOLHAS
 
| GERARFOLHAS
 
| COMFOLHAS
 
| COMFOLHAS
 
|}
 
 
 
=== Registar ===
 
Esta opção permite registar um novo habitat.
 
 
 
O sistema pede o identificador, o nome ('''Prompt.habitatName()''') (cadeia de caracteres) e a área do habitat ('''Prompt.habitatArea()''') (número inteiro), sendo registado o novo habitat.
 
 
 
Deve ser lançada a excepção '''DuplicateHabitatKeyException''', se existir um habitat com o mesmo identificador, não se realizando qualquer acção.
 
 
 
=== Alterar área ===
 
Esta opção permite alterar a área de um habitat.
 
 
 
O sistema pede o identificador do habitat assim como a nova área desse habitat ('''Prompt.habitatArea()''') (número inteiro).
 
 
 
=== Alterar influência em espécie ===
 
Esta opção permite alterar a influência de um habitat sobre uma espécie.
 
 
 
O sistema pede o identificador do habitat, o identificador da espécie e se a influência do habitat ('''Prompt.habitatInfluence()''') sobre a espécie indicada é positiva (resposta: '''POS'''), negativa (resposta: '''NEG'''), ou neutra (resposta: '''NEU'''). Se a resposta não corresponder a nenhum dos três valores, esta última pergunta é repetida até se obter uma resposta válida.
 
 
 
=== Plantar árvore ===
 
Esta opção permite introduzir uma nova árvore num habitat.
 
 
 
O sistema pede o identificador do habitat e o identificador da nova árvore a plantar. De seguida, pede-se o nome ('''Prompt.treeName()''') (cadeia de caracteres), a idade da árvore ('''Prompt.treeAge()'''), a dificuldade base de limpeza associada à árvore ('''Prompt.treeDifficulty()''') (número inteiro) e o tipo de árvore ('''Prompt.treeType()''') ('''PER''' para árvore de folha perene; '''CAD''' para árvores de folha caduca), registado-se a nova árvore. Se a resposta relativa ao tipo não corresponder a nenhum dos dois valores, esta última pergunta é repetida até se obter uma resposta válida.
 
 
 
Se já existir uma árvore com o mesmo identificador (em qualquer habitat), é lançada a excepção '''DuplicateTreeKeyException''', não se realizando qualquer acção.
 
 
 
A nova árvore deve ser apresentada na saída. O formato de apresentação é como descrito acima.
 
 
 
=== Consultar Árvores de um Habitat ===
 
Esta opção permite visualizar todas as árvores de um determinado habitat.
 
 
 
O sistema pede o identificador do habitat e apresenta as árvores que nele existem. O formato de apresentação é como descrito acima.
 
 
 
== Menu de Gestão de Vacinas ==
 
 
 
Este menu permite operar sobre vacinas e vacinações. A lista completa é a seguinte: [[#Visualizar|Visualizar]], [[#Registar|Registar]], [[#Vacinar|Vacinar]], [[#Consultar vacinações|Consultar vacinações]]. As secções abaixo descrevem estas opções.
 
 
 
{{CVSCode|As etiquetas das opções deste menu estão definidas na classe '''hva.app.vaccine.Label'''. Todos os métodos correspondentes às mensagens de diálogo para este menu estão definidos em '''hva.app.vaccine.Prompt''' e '''hva.app.vaccine.Message'''.}}
 
{{CVSCode|Estes comandos já estão implementados nas classes da ''package'' '''hva.app.animal''' (disponível no GIT), respectivamente: '''DoShowVaccine''', '''DoRegisterVaccine''', '''DoVaccinateAnimal''', '''DoShowVaccinations'''.}}
 
 
 
=== Visualizar ===
 
Esta opção permite visualizar todas as vacinas.
 
 
 
O formato de apresentação de cada vacina, uma por linha, é o seguinte:
 
<source lang="text">
 
 VACINA|idVacina|nomeVacina|númeroDeAplicações|espécies
 
</source>
 
 
 
O campo '''espécies''' contém os identificadores, separados por vírgulas, das espécies de animais que podem receber a vacina.
 
 
 
=== Registar ===
 
Esta opção permite registar uma nova vacina.
 
 
 
O sistema pede o identificador da vacina, o nome ('''Prompt.vaccineName()''') (cadeia de caracteres) da vacina e os identificadores das espécies que podem receber esta vacina ('''Prompt.listOfSpeciesKeys()''') (lista de identificadores separados por vírgulas -- os espaços brancos são irrelevantes nesta resposta). De seguida regista a nova vacina.
 
 
 
Deve ser lançada a excepção '''DuplicateVaccineKeyException''', se existir uma vacina com o mesmo identificador, não se realizando qualquer acção.
 
 
 
Se algum dos identificadores de espécies indicados for desconhecido, deve ser lançada a excepção '''UnknownSpeciesKeyException''', não sendo registada a nova vacina.
 
 
 
=== Vacinar ===
 
Esta opção permite registar a vacinação de um animal.
 
 
 
O sistema pede o identificador da vacina, o identificador do veterinário ('''Prompt.veterinarianKey()''') e o identificador do animal a vacinar. Se o identificador não for de um veterinário, deve ser lançada a excepção '''UnknownVeterinarianKeyException'''. Se o veterinário não tiver permissão para ministrar a vacina, deve ser lançada a excepção '''VeterinarianNotAuthorizedException''' e o comando não tem qualquer efeito. Se a vacina não for adequada ao animal, deve ser apresentada uma mensagem de aviso ('''Message.wrongVaccine()'''). Note-se que, neste caso, a vacinação acontece e os danos para o animal são registados.
 
 
 
=== Consultar vacinações ===
 
Esta opção permite listar o histórico de vacinações ordenado pela ordem em que as vacinas foram aplicadas.
 
 
 
O sistema lista todas as vacinas aplicadas, usando o seguinte formato:
 
<source lang="text">
 
 REGISTO-VACINA|idVacina|idVeterinário|idEspécie
 
</source>
 
 
 
== Menu de Consultas ==
 
 
 
O menu de consultas permite efectuar pesquisas sobre as entidades do domínio e suas relações. Sempre que for feita uma consulta e nenhuma entidade satisfizer as condições associadas ao pedido, nada deve ser apresentado.
 
 
 
A lista completa das consultas é a seguinte: [[#Consultar animais de um habitat|Consultar animais de um habitat]], [[#Consultar vacinas de um animal|Consultar vacinas de um animal]], [[#Consultar actos médicos de um veterinário|Consultar actos médicos de um veterinário]], [[#Consultar vacinas dadas com incúria|Consultar vacinas dadas com incúria]]. As secções abaixo descrevem estas opções.
 
 
 
{{CVSCode|As etiquetas das opções deste menu estão definidas na classe '''hva.app.search.Label'''. Todos os métodos correspondentes às mensagens de diálogo para este menu estão definidos em '''hva.app.search.Prompt''' e '''hva.app.search.Message'''.}}
 
{{CVSCode|Estes comandos já estão implementados nas classes da ''package'' '''hva.app.search''' (disponível no GIT), respectivamente: '''DoShowAnimalsInHabitat''', '''DoShowMedicalActsOnAnimal''', '''DoShowMedicalActsByVeterinarian''', '''DoShowWrongVaccinations'''.}}
 
 
 
=== Consultar animais de um habitat ===
 
 
 
O sistema pede o identificador do habitat, apresentando os animais que residem nesse habitat.
 
 
 
O formato de apresentação é como indicado para a listagem de animais.
 
 
 
=== Consultar vacinas de um animal ===
 
 
 
O sistema pede o identificador do animal, apresentando as vacinações (por ordem de aplicação).
 
 
 
O formato de apresentação é como indicado para a listagem de vacinações.
 
 
 
=== Consultar actos médicos de um veterinário ===
 
 
 
O sistema pede o identificador de um funcionário. Se o identificador não for de um veterinário, deve ser lançada a excepção '''UnknownVeterinarianKeyException'''. Caso contrário, são apresentadas todas as vacinações por ele realizadas (por ordem de aplicação).
 
 
 
O formato de apresentação é como indicado para a listagem de vacinações.
 
 
 
=== Consultar vacinas dadas com incúria ===
 
 
 
O sistema apresenta todas as ocorrências de vacinações que provocaram problemas de saúde aos animais.
 
 
 
O formato de apresentação é como indicado para a listagem de vacinações (por ordem de aplicação).
 
 
 
= Inicialização por Ficheiro de Dados Textuais =
 
 
 
Por omissão, quando a aplicação começa, não contém nenhuma informação e está na estação '''Primavera'''. No entanto, além das opções de manipulação de ficheiros descritas no [[#Salvaguarda do Documento Actual|menu principal]], é possível iniciar exteriormente a aplicação com um ficheiro de texto especificado pela propriedade Java '''[[#Execução dos Programas e Testes Automáticos|import]]'''. Quando se especifica esta propriedade, a aplicação é povoada com os objectos correspondentes ao conteúdo do ficheiro indicado.
 
 
 
No processamento destes dados, assume-se que não existem entradas mal-formadas e assume-se que os identificadores referidos numa entrada já foram previamente descritos. Sugere-se a utilização do método '''String.split()''' para dividir uma cadeia de caracteres em campos.
 
 
 
No formato abaixo: para os habitats, só os 4 primeiros campos são obrigatórios, correspondendo os opcionais a árvores implantadas no recinto; para os tratadores, só os 3 primeiros campos são obrigatórios, correspondendo os opcionais a habitats; e, para os veterinários e vacinas, só os 3 primeiros campos são obrigatórios, correspondendo os opcionais a espécies de animais.
 
 
 
{{CollapsedCode|Formato do ficheiro de entrada textual|
 
<source lang="text">
 
ESPÉCIE|id|nome
 
ÁRVORE|id|nome|idade|dificuldade|tipo
 
HABITAT|id|nome|área|idÁrvore1,...,idÁrvoreN
 
ANIMAL|id|nome|idEspécie|idHabitat
 
TRATADOR|id|nome|idHabitat1,...,idHabitatN
 
VETERINÁRIO|id|nome|idEspécie1,...,idEspécieN
 
VACINA|id|nome|idEspécie1,…,idEspécieN
 
</source>
 
}}
 
 
 
Se alguma das listas for vazia, então não se apresenta o último campo (nem o separador).
 
 
 
No seguinte exemplo, o conteúdo do ficheiro inicial ('''test.import''') correspondente à folha apresentada a seguir.
 
{{CollapsedCode|Exemplo de ficheiro de entrada textual|
 
<source lang="text">
 
ESPÉCIE|C10|ave
 
ESPÉCIE|C8|mamífero
 
ESPÉCIE|C1|peixe
 
ÁRVORE|T1|Pinheiro 1|5|20|PERENE
 
ÁRVORE|T4|Pinheiro 4|60|20|PERENE
 
ÁRVORE|T2|Oliveira|1200|10|PERENE
 
ÁRVORE|T6|Figueira|5|10|CADUCA
 
ÁRVORE|T3|Plátano|300|20|CADUCA
 
ÁRVORE|P1|Plátano|100|20|CADUCA
 
ÁRVORE|F30|Figueira|50|20|CADUCA
 
HABITAT|AR1|Aldeia dos Macacos|20|T3,P1,F30,T2
 
HABITAT|AR2|Floresta tropical|30|T1,T4,T6
 
HABITAT|AR3|Deserto|3
 
ANIMAL|A1|Alex|C10|AR1
 
ANIMAL|A2|Nemo|C1|AR2
 
ANIMAL|AA|Bobi|C8|AR1
 
ANIMAL|MA|Chita|C8|AR2
 
TRATADOR|W2SO4|John Figueiredo|AR2,AR3
 
TRATADOR|W2O|Rohit Figueiredo|AR1
 
TRATADOR|W24|Rohit Figueiredo
 
VETERINÁRIO|V2|Jorge Figueiredo|C10,C8,C1
 
VETERINÁRIO|V4|Filomena Figueiredo
 
VETERINÁRIO|VR|Abdul Figueiredo|C8
 
VACINA|V3|Tétano|C8
 
VACINA|V200|Parasitas intestinais|C10,C8,C1
 
VACINA|V42172|Tétano|C10
 
VACINA|Vexperimental|Gripe A1|C8
 
</source>
 
}}
 
 
 
{{Suggestion|A codificação dos ficheiros a ler é garantidamente [[wp:UTF-8|UTF-8]].}}
 
{{Suggestion|Note-se que o programa nunca produz ficheiros com este formato.}}
 
 
 
= Execução dos Programas e Testes Automáticos =
 
 
 
Usando os ficheiros '''test.import''', '''test.in''' e '''test.out''', é possível verificar automaticamente o resultado correcto do programa. Note-se que é necessária a definição apropriada da variável '''CLASSPATH''' (ou da opção equivalente '''-cp''' do comando '''java'''), para localizar as classes do programa, incluindo a que contém o método correspondente ao ponto de entrada da aplicação ('''hva.app.App.main'''). As propriedades são tratadas automaticamente pelo código de apoio ('''po-uilib''').
 
<source lang="text">
 
        java -Dimport=test.import -Din=test.in -Dout=test.outhyp hva.app.App
 
</source>
 
 
 
Assumindo que aqueles ficheiros estão no directório onde é dado o comando de execução, o programa produz o ficheiro de saída '''test.outhyp'''. Em caso de sucesso, os ficheiros das saídas esperada ('''test.out''') e obtida ('''test.outhyp''') devem ser iguais. A comparação pode ser feita com o comando:
 
<source lang="text">
 
        diff -b test.out test.outhyp
 
</source>
 
 
 
Este comando não deve produzir qualquer resultado quando os ficheiros são iguais. Note-se, contudo, que este teste não garante o correcto funcionamento do código desenvolvido, apenas verificando alguns aspectos da sua funcionalidade.
 
<!--
 
[[category: Ensino]]
 
[[category:PO]]
 
[[category: Projecto de PO]]
 
[[en:Object-Oriented Programming]]
 
-->
 

Latest revision as of 14:48, 6 September 2024