Antes de eu mostrar a solução desse exercício,
eu vou fazer uma pausa aqui
e vou abrir minha ferramenta CASE
chamada StarUML.
Vou usar o Default,
a abordagem Default.
Vejam que eu tenho diagramas de análise
mais genéricos e mais alto nível,
e diagramas mais técnicos, tá,
sendo que é de design de projeto.
Vejam que eu não menti pra vocês com relação à versão que eu uso,
ela tá ali, ó.
Aqui é a ferramenta que permite eu fazer a maquete
do meu software.
Lá, vocês tão trabalhando com a classe
Universidade, não é isso?
Eu viria aqui, escrever aqui, ó.
Universidade.
Só que aqui eu vou trazer outro exemplo, não trabalhar nesse
exemplo prático que eu tô fazendo nesse preciso momento aqui.
Eu não vou usar a classe Universidade.
Insisto, tá. Esse StarUML aqui ele é gratuito,
você baixa da internet, ferramenta gratuita.
Eu não vou querer criar uma classe Universidade.
Eu vou criar uma classe, sei lá eu, Jogador.
Imaginem que eu tô fazendo um jogo.
Jogador.
Um joguinho, sei lá eu, um Pacman, ou algo assim
Bom, vocês sabem que toda
sistema orientado a objetos
vocês tem que começar a partir de uma classe principal
que eu posso chamar de Principal e, nesse caso, eu vou chamar de Jogo.
Eu posso, ainda assim,
usando esse ferramental vir aqui e criar um estereotipo.
É algo que lembra,
conta bem rapidamente,
algo sobre essa classe.
Então eu vou contar que esse aqui é um Principal.
E o Jogador o que que ele é?
Jogador ele é um Personagem do Jogo.
Então eu posso pôr meu estereotipo aqui, ó,
Personagem.
Inclusive, nada impede de eu escrever corretamente.
Ora,
aonde que vai ser criado o Jogador?
Vai ser criado na classe Principal.
Então, tá aqui, ó,
Como é que eu crio um objeto de Jogador
agregado, aí, com a Principal em termos de UML?
Eu venho aqui e escrevo:
Jogador, sei lá eu, jog.
Única coisa é que a UML, ela não usa o formato
pelo menos não nessa ferramenta CASE aqui
que respeita a UML, a gramática da UML.
Ele não usa muito o formato do C++, tá,
ele usa um formato mais Pascal, mais ALGOL.
Ele faz assim,
mas também não é uma complicação enorme
e, ainda posso contar que a coisa aqui ela é privada.
Tá, mas como é que graficamente eu conecto isso?
Bom, já que
o Jogo tem o Jogador
eu posso criar uma relação de composição.
Pessoal, a gente não fica usando linhas assim, tortas, tá
a gente tá aqui fazendo um processo de engenharia
temos que ser cartesianos. Retilíneo.
Aqui, ó.
Navegável, depois eu explico o porquê navegável.
O Jogo agrega um Jogador.
Eu posso ter cardinalidades entre as relações.
Muito bem.
E o Jogador é agregado
por um Jogo.
Isso aqui então em termos de UML
É como se faz uma
agregação forte, uma composição.
Agora eu quero ter uma outra classe aqui
Imagine que eu tenho a classe aqui
Inimigo.
Inimigo, o que ele é? Ele é um personagem também.
Então, vamos pôr um estereotipo nele.
Personagem.
Legal.
Vamos agora fazer uma agregação.
Por quê?
Porque o Inimigo vai ser criado lá
no âmbito da classe Principal, né,
porque isso aí é o nosso mantra.
Até quantos
Inimigos eu posso ter no jogo?
Imagino que vocês querem começar modestos
vocês querem começar ter entre 1 ou 2.
Aqui, ó.
Matematicamente você tá dizendo que é 1 ou 2.
Poê um limite.
Se parar pra pensar, isso aqui é um pouco da Teoria de Conjuntos, tá,
Teoria de Conjuntos
usado graficamente,
porque a Teoria de Conjuntos
serve pra definir os conjuntos de objetos na prática
e como esses objetos se relacionam.
Muito bem.
Esses Inimigos vão estar agregados em quantos Jogos?
Em um jogo só.
Aqui eu posso criar, então,
ini1 do tipo Inimigo.
Opa, aqui é privado.
Professor, mas o senhor disse que é entre 1 e 2.
Verdade.
Isso respeito, eu tenho 1
então tá respeitando aqui
a minha formulação matemática,
a minha cardinalidade.
Muito bem.
Agora eu posso criar
uma associação
entre o Jogador e o Inimigo.
Imaginem que vocês estão fazendo um joguinho gráfico, lá,
aonde o Inimigo vai ficar perseguindo o Jogador.
Para tal, é necessário
que o jogador, aliás, que o Inimigo
conheça o Jogador.
Tá vendo, ó, é direcional.
Só Inimigo vai conhecer Jogador.
Jogador não vai conhecer o Inimigo.
Por isso da seta aí.
Garantir que isso aqui vai ficar retilíneo.
Aqui é uma associação, tá.
Isso significa que, tecnicamente,
o Inimigo aqui
ele vai ter
um ponteiro pJog
Jogador ponteiro.
Lembre que isso aqui já é um Diagrama de Projeto,
ou seja, ele tá mais perto da implementação do que de análise.
Qual é o nome ou
o entendimento que a gente dá pra essa associação entre eles?
Por que que o Inimigo tem um ponteiro
pro Jogador?
Ponteiro inclusive que pode ser privado, né.
Deve ser privado.
Bom, o Inimigo tem esse ponteiro pra Jogador,
porque ele quer perseguir.
Então, per-se-guir.
O inimigo vai perseguir quantos jogadores?
Bom, só tenho um jogador, né,
não tenho muita opção.
Cada Inimigo vai perseguir um Jogador.
E o Jogador é perseguido por quantos Inimigos?
Bom, matematicamente,
vai ser 1 ou 2.
Eu posso fixar, mesmo que tenha 2,
eu posso fixar que seja um só.
Pra que o jogador não fique se batendo
com dois perseguidores.
Só com um perseguidor.
Vamos colocar 1 aqui.
Muito embora eu pudesse se...
quisesse um jogo mais complexo, mais difícil
colocar aqui 1 ou 2.
Muito bem.
Tem outras coisas que eu posso fazer aqui, tá.
Em cada Classe,
vocês tão vendo que isso é a definição de classes graficamente, tá.
Aqui temos uma maquete do meu software
e aqui eu tô usando um outro exemplozinho
como se fosse um jogo.
Eu posso criar, então, além de atributos,
eu posso também criar métodos.
Vou exemplificar, sei lá eu, aqui no Jogador.
Jogador, por exemplo,
eu posso construir aqui
uma função construtora pra ele.
Você sabe que toda classe tem que ter
uma construtora sem parâmetros.
Eu posso ter aqui também um atributo,
um atributo, sei lá eu,
vou colocar aqui, por exemplo,
numVidas, o número de vidas que o Jogador têm,
e eu vou colocar ele do tipo inteiro aqui.
Professor, a construtora não tem parâmetro aqui
então ele vai, normalmente, zerar esse número de vidas.
Como é que eu faço pra colocar o número de vidas?
Ora, eu posso criar uma função aqui
setVidas() e um getVidas().
Antes disso, pra fins de organização eu vou
criar a destrutora. Jogo.
Construtora e destrutora.
Tá faltando o til (~) ali, tá.
Por quê? Porque em UML
ele não faz igual em C++, mas a gente já vai resolver essa questão.
Como eu dizia,
vamos criar aqui agora
um setVidas()
que vai receber como parâmetro
um inteiro n
que vai servir pra alimentar o número de vidas obviamente.
E o retorno dessa função aqui é void.
Vamos fazer um getVidas() também.
Fazer um set e get do caso do número de vidas ali.
getVidas().
Não tem parâmetro
e tem, em contrapartida, um retorno que é inteiro.
Vejam que as funções estão todas públicas.
Enquanto que o método... aliás, o atributo aqui
ele vai ter que ficar privado.
Como é que eu diferencio construtora e destrutora?
Aqui, nessa ferramenta,
eu tenho que clicar em "Operações"
e lembrar que funções de classes
são chamadas de funções-membro,
de métodos ou de operações, tá.
Nessa ferramenta as vezes eu vou chamar de operações.
Então, eu vou ali
e eu consigo pra essa função
ter um estereotipo dela aqui
que é um estereotipo de criação.
Muito bem.
Pra essa outra função aqui.
Clique na classe.
Agora eu vou nas operações dessa classe.
Vou escolher a destrutora
e vou estereotipá-la como destrutora.
E tá aqui.
Obviamente, gente, que eu posso e devo
vir ali e criar a construtora e destrutora
pra classe Jogo,
construtora e destrutora pra classe Inimigo,
criar aqui pra classe Inimigo, sei lá eu,
um setPJgo() e um getPJog()
Aqui eu posso ter uma função Executar(). Posso e devo.
na classe Principal, tá.
E por aí vai.
Inclusive, a Executar() eu vou fazer aqui.
Executar(),
que vai ser do tipo void.
Legal.
Bom, eu posso, como vocês já entenderam,
trabalhar melhor esse diagrama aqui, tá.
Deixar ele mais completo,
mas aqui o meu ponto é só mostrar pra vocês a ferramenta CASE.
Inclusive, eu vou ter que salvar esse projeto em algum lugar.
Vou clicar em Simão.
Se eu não me equivoco
nós estamos no ano de 2020,
em plena pandemia.
Aqui tem as disciplinas.
Aqui eu tenho o Estudo Dirigido, tá.
Disciplinas e Curso, mas enfim o Estudo é Dirigido.
Aqui eu posso criar um novo diretório
que vai ser, sei lá eu,
ExemploUML1.
E vou pôr aqui
Exemplo1_Jogo, quiçá.
Legal.
Agora salvou esse projeto.
Então, como eu dizia,
a ideia aqui é mostrar pra vocês terem uma ideia
do que é uma ferramenta CASE,
e como é que eu faço a maquete de um software.
Tal qual, eu fiz a maquete aqui
desse sisteminha Jogo
cujos os requisitos a gente foi falando aqui em tempo de execução, né,
falando, tá.
Por quê? Porque ele é um exemplo num ambiente de aprendizado,
mas eu poderia, à luz dos requisitos lá do...
já expostos do... Sistema Acadêmico
criar também um diagrama de UML's
de UML, perdão,
tal qual eu fiz aqui pra esse joguinho.
Outra coisa interessante que eu queria mostrar pra vocês aqui, tá
além na capacidade de criar as nossas maquetes
pros nossos softwares orientados a objetos usando a UML,
tem uma peculiaridade.
Eu posso gerar código
a partir desses dados.
Eu posso vir aqui, ó, em "Tools"
e gerar código em C++.
Inclusive, antes de começar essa exposição, eu tentei e deu erro.
Não funcionava.
Eu fui obrigado a voltar aqui em "Options"
e clicar...
ali em C++
e clicar aqui, ó, isso tava desclicado.
Generate codes even when...
Mesmo quando não tem perfil de geração de código, tá.
Então,
tem que dar um clique pra aceitar ali, ó.
Dei um clique daí ele voltou a funcionar.
Eu dei "Cancel", porque eu já tinha feito isso antes.
Vocês vão dar "Ok" ali.
Então, a partir de então foi possível gerar código.
Vamos gerar código.
Aqui,
eu vou escolher gerar código
a partir do meu modelo de projeto
e não de análise, mesmo porque de análise eu não tenho, não fiz.
Vou dar um "Next".
Quais classes eu quero gerar?
Quero gerar de todas.
Jogador, Jogo e Inimigo.
Muito bem, avancemos um pouquinho.
Daí ele vai perguntar onde eu quero gerar isso.
Bom, a gente é organizado, né,
vai colocar a geração de código
lá no mesmo lugar onde está o projeto.
Tô fazendo besteira, tô incluindo no CD.
Meu PC é tão antigo que tem CD.
2020.
Estudo Dirigido.
ExemploUML1.
Vamos gerar ali.
Eu vou dar um "Next".
Eu tenho certeza que vocês vão ler o que tá aqui, tá.
Leiam com atenção
pra saber o que vocês tão fazendo.
Se vocês forem gerar código para fins
de experimentação, saber que isso é possível.
Bem entendido.
Vamos lá.
Então, eu gerei o código, e cadê?
Ué, ele tá lá na pasta que eu indiquei.
Então, pra isso, eu vou precisar ir na pasta.
Trazer aqui o meu Explorer.
Tá ali, ó. De fato ele gerou o código.
Se vocês olharem aqui
Eu posso olhar, por exemplo,
a classe Jogo.
Tá aqui ó, gente, ele criou
do jeito dele, tá,
mas ele criou uma classe Jogo.
Eu costumo, por exemplo, programar
primeiro a parte privada
e depois a parte pública
ele, nessa geração, faz outramente.
Não tem problema, também funciona,
duas maneiras que funcionam
são padrões de codificação distintos,
mas funcionam.
Vamos olhar o respectivo .cpp.
Tá aqui.
Microsoft. Ok.
Vejam que tá ali, ó.
Não tem nada na função executar().
Bom, certamente que não tem nada, porque eu não fiz nada aí.
Não programei nada aí nessa função.
Aliás, eu não modelei nada com relação a função,
eu só modelei que ela existe.
Eu não vim aqui
ou lá no modelo
em termos daquela função
e cliquei naquela função e criei, por exemplo, um fluxograma
dizendo como é que vai ser o algoritmo que vai estar lá dentro.
Se eu tivesse feito isso,
criado essa espécie de fluxograma,
e tivesse usando uma ferramenta profissional
ela consegue...
ela poderia conseguir gerar parte do código.
Quanto mais detalhado tá o teu fluxograma
mais completo é o código gerado, em tese.
Bom, eu posso olhar as outras classes que foram criadas também.
Olha lá o Jogador.
Criou o jogador.
Criou tudo que a gente previu.
.cpp, obviamente, vai ter só pronto, aqui, os métodos
pra que a gente coloque a implementação, né.
Ainda tem o Inimigo.
Aqui ele não gerou
Inimigo.cpp, tão vendo?
Ué, e por quê?
Porque, na verdade, provavelmente eu não coloquei
nenhum método lá na minha classe.
Se eu voltar,
de fato não coloquei ainda.
Se eu tivesse colocado, e mandasse gerar,
aí ele ia criar o Inimigo.cpp
Inclusive posso criar aqui uma função aqui.
Perseguir, por exemplo, ou algo assim, tá.
Perseguir().
Também, obviamente,
eu teria que ter aqui
a construtora e destrutora
tal qual eu fiz ali com Jogador.
Legal.
Como eu dizia pra vocês, tá,
isso aqui é um Diagrama de Classes.
Agora eu posso, na UML, usar outros diagramas.
que são complementares do Diagrama de Classes
ou permite chegar no Diagrama de Classes, tá.
Eu consigo dar um exemplo a título de curiosidade, aqui
porque eu imagino que vocês tão curiosos.
Jogador. Jogador tem ali, por exemplo,
o getVidas().
Eu posso criar um modelo pra essa função getVidas().
Tá ali a função getVidas()
aí eu venho aqui, ó,
e adiciono um novo diagrama pra essa função
que diagrama vai ser esse?
Vai ser aquele Diagrama de Atividades
Dito de maneira grosseira,
uma espécie de fluxograma moderno.
Tá aqui, ó.
Vou ter um estado inicial.
Vou ter um estado final.
Tem a hora que entra e a hora que sai da funçãozinha.
E aqui eu posso ter, por exemplo,
uma decisão, aliás, uma ação.
Posso ter decisão também, tá, mas não é o caso.
Que que ele vai fazer nessa...
nessa função?
Ele vai retornar
o atributo, que atributo que é mesmo?
vidas, obviamente, numVidas.
numVidas.
Aqui, ó, eu fiz a modelagem.
Modelagem agora da dinâmica, ou seja,
daquela função em específico.
Obviamente que eu tenho que conectar as coisas.
Claro que essa função é uma função simples, tá.
A função perseguir(), por exemplo
ele já vai ter uma modelagem mais complexa.
Ela já vai ter que
levar em consideração posição
do Jogador, posição do Inimigo
coisa que não tá nem modelado, inclusive, aqui, ó.
Não pus x, y em nenhum deles aqui,
mas se você tivesse x, y aqui e x, y ali
perseguir() ia ter que levar em consideração
o x, y Inimigo e o x, y do Jogador.
Logo, uma modelagem
pra função da classe Inimigo
no tocante a sua função perseguir(),
ia ser muito mais complexa
do que essa que a gente fez
que o getVidas() do Jogador.
É só pra vocês saberem que é possível, então,
eu modelar o algoritmo que vai tá dentro de cada
função-membro, de cada método, de cada classe.
E aí, se essa ferramenta, fosse uma ferramenta mais
potente, né, industrial e tal,
na geração de código, ele já ia
fazer o preenchimento do código lá na função.
Então, aqui em jogador, por exemplo, ele já ia gerar o código aqui,
mas ele não gera.
Pelo menos, ao melhor do meu conhecimento, ele não gera.
Até pode tentar aqui, tá.
Nessa ferramenta, bem entendido.
Salvar, né, porque aí ele salva tudo.
Tools.
cpp.
Generate Code.
A gente tá falando ambiente de projeto
a gente quer essas três classes.
Bom, aqui ele não é muito esperto, pelo jeito.
Poderia já lembrar
qual o diretório que eu usei por último
mas ele não tá querendo fazer isso.
Então, eu vou dar uma mão pra ele.
Ok.
E aqui estamos nós.
vocês vão nessas opções, tá.
Next.
E ele gerou.
A nossa curiosidade agora é saber
se ele gerou o código aqui pro...
automaticamente, né
pra função getVidas() lá que
tá na classe Personagem.
Então eu vou direto pra, código gerado de Jogador.
Foi gerado agora, ó, 15h39, certinho.
Ali.
É, de fato ele não gera código pra mim ainda, tá,
pelo menos, não nessa versão do StarUML.
Mesmo esse código que é simples, tá.
Já o Rhapsody, por exemplo,
uma ferramenta mais robusta, industrial,
ela ia gerar, insisto.
Agora na classe Inimigo, eu coloquei a função perseguir().
Então, ele já gerou agora um Inimigo.cpp que tem a funçãozinha ali tá.
Professor, por que ele não tem aqui a construtora e destrutora?
Porque eu não modelei.
Eu tenho que modelar pra ele gerar.
Joia.
Isso aqui pessoal, insisto,
é só pra vocês se simpatizarem um pouco
com essa situação de modelagem, tá.
Ficarem mais sensibilizados
sobre o que que é a modelagem.
Eu vou fechar a ferramenta CASE,
e voltar pro meu grupo de slides em questão,
que é o 3 parte A.