A apresentação está carregando. Por favor, espere

A apresentação está carregando. Por favor, espere

Padrões de Projeto Aula 3 – Padrão Strategy.

Apresentações semelhantes


Apresentação em tema: "Padrões de Projeto Aula 3 – Padrão Strategy."— Transcrição da apresentação:

1 Padrões de Projeto Aula 3 – Padrão Strategy

2 Padrões de Projeto - Strategy
Padrão Strategy

3 Padrões de Projeto - Strategy
Imagine que os donos da Sega lhe contrataram para implementar o jogo do Mortal Kombat III.

4 Modelo Como vocês implementariam este jogo? Conjunto de lutadores
Atacar Defender Mover Especificamente socar(), chutar() Defender  já é específico andar(direção), pular(direção) Padrões de Projeto - Strategy O MK3 tem um conjunto de lutadores, onde cada um pode atacar e defender. Mas atacar e defender são conceitos/comportamentos muito gerais. Vamos tornar isto mais específico. Todos os nossos lutadores podem andar(direção), pular(direção), socar(), chutar() e defender(). Como é que vocês fariam isso?

5 Modelo Padrões de Projeto - Strategy
As implementações de socar(), chutar(), defender(), andar(direcao) e pular(direcao) poderiam ser concretas e ficariam na superclasse. Assim todo novo lutador não precisaria reescrever esses comportamentos. (Herança) Desenha() deve ser abstrato. Desenhar seria o método responsável por apresentar/pintar o lutador na tela. Deve ser abstrato porque todos os lutadores são diferentes (em termos de aparência), logo, cada novo lutador inserido ao projeto deve fornecer uma implementação concreta para o método desenha (especificando suas características), para que a classe principal possa utilizar o método desenha() de maneira polimórfica. E assim o nosso projeto estaria flexível para cada novo jogador. Faz sentido né?

6 Novas funcionalidades
Ambos os lutadores atiram! Como devemos modelar esta nova funcionalidade? Padrões de Projeto - Strategy E se nós colocássemos o método atirar() na superclasse Lutador? Fica legal? Assim nós conseguiríamos reuso do código, e o Nightwolf e o Stryker não precisariam implementar códigos semelhantes. Qual o problema disso? Todo Lutador que nós implementássemos poderia atirar, o que não é o caso... Liu Kang, por exemplo, poderia atirar.

7 Novas funcionalidades
Interfaces? Padrões de Projeto - Strategy O que vocês acham dessa implementação? Parece ser legal né? Agora nós não quebramos mais a lógica de implementação. Todo novo lutador só irá atirar se implementar a interface Atirador. O que é legal da interface Atirador? Agora nós podemos utilizar o método atirar() de modo polimórfico. Ok. Mas tem um detalhe que não tá legal. Esse código não é reutilizável. Tudo bem que o método atirar() de Stryker e NightWolf devem ser diferentes, inclusive porque eles usam diferentes armas. Mas se nós quisermos adicionar ao nosso jogo o personagem ErronBlack... (nas versões que eu joguei ele não existia, mas pesquisei no google e ele aparentemente é um “caubói do velho oeste”... Uiiii que meda.. Kkkkkk) Enfim, vocês percebem que nós basicamente reescreveríamos o mesmo código para Stryker e ErronBlack? E se nós quiséssemos criar um outro personagem que possui como um dos comportamentos de ataque a habilidade de atirar com uma arma de fogo convencional, assim como Stryker e Erron Black? Basicamente copiaríamos e colaríamos o mesmo código nesses personagens. ISTO NÃO É LEGAL!! Se futuramente quisermos mudar algum detalhe no modo como os personagens deveriam atirar com arma de fogo, basicamente deveríamos fazer a alteração em todos os personagens.

8 Novas Funcionalidades
Lançar magia! Sub Zero (lança gelo) Rayden (lança raio) Shang Tsung (lança bola de fogo) Jax (lança bola de fogo) Liu Kang (lança bola de fogo) Padrões de Projeto - Strategy Pra ficar mais claro como isso poderia ser uma “bola de neve”. Agora nós queremos adicionar ao nosso modelo alguns lutadores que Lançam Magia, ou seja, são bruxos. É fato que em Mortal Kombat nós temos vários lutadores que lançam magia, estes (no slide) são alguns deles, provavelmente deve haver mais. Com o pensamento análogo ao que tivemos anteriormente, faz sentido que nós criemos uma interface Bruxo, na qual todos os lutadores que lançam magia deveriam implementar. Assim nós conseguiríamos utilizar o método lancaMagia() de maneira polimórfica.

9 Padrões de Projeto - Strategy
Mas aqui nós temos o mesmo problema que tivemos em Atirador. A interface nos dá o poder do polimorfismo, mas não nos dá o poder do reuso de código. Nesse caso, é ainda mais grave. Temos um comportamento que se repete em 3 lutadores: tanto Jax, como ShangTsung como LiuKang lançam bola de fogo. Isto quer dizer que nós teremos métodos basicamente iguais, ou pelo menos, bem semelhantes. Alguém discorda??? (se sim me mande pra conversarmos...) Mais uma vez, temos o problema da mudança de código. Se por algum acaso, precisarmos mudar a forma como o lancaMagia é implementado para lancar uma bola de fogo, teremos que ir nas 3 classes e fazer a alteração de forma local. Isso pode ficar ainda pior a medida em que adicionarmos novos lutadores (numa futura implementação de mortal kombat X).

10 Padrões de Projeto - Strategy
Temos que nos proteger contra essa característica natural no desenvolvimento de software. Como podemos fazer isso? Sistemas bem projetados são mais protegidos contra alteração. Quando necessárias, essas alterações são de menor porte possível. Qual é a única coisa com a qual podemos contar sempre no desenvolvimento de software? ALTERAÇÃO

11 Separando o que muda do que fica igual
Quais comportamentos são imutáveis? socar(), chutar(), defender(); Quais comportamentos são mutáveis? atirar(), lancarMagia(); O que devemos fazer? Separar o que muda do que fica igual! Como? Que tal criar um conjunto de classes (completamente separadas de Lutador) para cada comportamento? Cada conjunto de classes irá conter todas as implementações possíveis para seu comportamento. Ex.: teríamos uma classe para atirar com arma de fogo, outra classe para atirar flechas, etc. Padrões de Projeto - Strategy E agora, o que fazemos? Além do problema com atirar() e lancarMagia(), a classe Lutador parece estar ok. Dizemos isso porque tudo que está em Lutador não varia. Todos eles socam, chutam e se defendem igualmente.

12 Separando o que muda do que fica igual
Padrões de Projeto - Strategy

13 Desenvolvendo os comportamentos de Lutador
Como vamos desenvolver o conjunto de classes que implementam os comportamentos de atirar e lançar magia? Padrões de Projeto - Strategy

14 Desenvolvendo os comportamentos de Lutador
Utilizaremos interfaces! Padrões de Projeto - Strategy Agora nós utilizamos uma interface para representar cada comportamento, e cada implementação de comportamento irá implementar uma dessas interfaces. Agora, ao invés de cada Lutador implementar uma dessas interfaces, nós teremos comportamento específicos implementando-as. Ex.: ao invés de Nightwolf implementar a interface Atirador, nós teremos a classe “AtirarComArcoEFlecha” que implementa a classe Atirador. A ideia é que todo lutador tenha uma referência Atirador. Assim, todo lutador poderia, em tese, atirar. Se um novo lutador surgir com um novo comportamento de Atirador, esse comportamento deve ser implementado, e a classe Lutador simplesmente não precisa ser alterada. A variável de Atirador pode referenciar este novo comportamento. E se um lutador não for atirador. Daí ele teria uma referência a um comportamento que não atira (“NaoAtirar”). Por composição podemos criar novos Lutadores sem precisar alterar a classe Lutador, e a classe “MortalKombat”. Alterações mínimas seriam necessárias se novos tipos de comportamento existissem. Como vamos mostrar adiante.

15 PROGRAME para uma SUPERCLASSE!
Pela vez: PROGRAME para uma SUPERCLASSE! Padrões de Projeto - Strategy Só assim conseguimos utilizar o polimorfismo com eficiência!

16 Integrando o comportamento de Lutador
abstract class Lutador{ protected ComportamentoAtirador comportamentoAtirador; protected ComportamentoBruxo comportamentoBruxo; //... public void atirar(){ comportamentoAtirador.atirar(); } public void lancarMagia(){ comportamentoBruxo.lancarMagia(); Padrões de Projeto - Strategy As variáveis de comportamento são declaradas com o tipo da interface (superclasse). Assim conseguimos atribuir qualquer subclasse àquela variável, i.e., qualquer comportamento pode ser atribuído. Ex.: comportamentoAtirador pode receber um objeto do tipo “AtirarComArmaDeFogo”, “AtirarComArcoEFlecha”, “NaoAtirar”. Isso pode ser feito em tempo de execucao, e quando novos comportamentos de atirar aparecerem, nós não precisamos mudar Lutador, nem a classe ringue. Em vez de lidar com o comportamento de atirar em si, o objeto Lutador delega esse comportamento ao objeto relacionado por “ComportamentoAtirador”.

17 Padrões de Projeto - Strategy
Esses #, que significam protected, poderiam ser configurados como private. Dêem uma olhadinha em Strategy.rar. 

18 TEM-UM pode ser melhor do que É-UM
Quando puder, sempre use composição ao invés de herança... Lembre-se disto!  Pra que serve a herança? Resp.: um de seus objetivos é o reuso de código. Existe outra maneira de reutilizar código senão através da herança? Resp.: Sim, através de composição! Ao invés de herdar seus comportamentos, os lutadores obtêm seu comportamento ao serem compostos com o objeto de comportamento certo. Sistemas que utilizam composição possuem muito mais flexibilidade do que os que usam herança. Conseguimos reuso de código de maneira flexível e com maior poder de manutenção. A composição permite que os Lutadores alterem seu comportamento em tempo de execução. (lembra do Shang Tsung?) Padrões de Projeto - Strategy

19 Exercício Considerando o design que nós acabamos de modelar, implemente (papel) a classe Lutador e uma das seguintes classes, que É-UM Lutador: Padrões de Projeto - Strategy

20 Solução class NightWolf extends Lutador{ public NightWolf(){
comportamentoAtirador = new AtirarComArcoEFlecha(); comportamentoBruxo = new LancarNada(); } Padrões de Projeto - Strategy

21 Ops... Inicialmente eu achei que NightWolf não lançava magia (de verdade, eu não sabia...) Aparentemente, ele (MK3) possui uma conexão muito forte com o Raiden (MK2), e lança raios em seus oponentes. Vamos considerar isso como uma magia. Como deveríamos proceder para consertar NightWolf? Padrões de Projeto - Strategy Nightwolf foi o primeiro personagem indígena americano do Mortal Kombat e fez sua primeira participação emMortal Kombat 3. Foi apresentado como um historiador e shaman. Ele é um sábio e poderoso guerreiro dedicado a fazer o bem, e faz contato com Raiden através de visões. Nightwolf consegue conciliar energias espirituais internas e externas, melhorando seu desempenho nas batalhas. Ele é o tipo de pessoa que prefere trabalhar sozinho a acompanhado. Nightwolf foi alertado sobre a invasão de Earthrealm por uma visão de Raiden. Assim, ele teve tempo de preparar-se para os eventos posteriores, inclusive os ataques das tropas de extermínio do diabólico imperador Shao Kahn. Ele se uniu aos outros guerreiros da Terra e defrontou-se com as tropas de Kahn, vencendo a batalha e salvando o mundo. Nightwolf possui o poder de convocar machadinhas, arco, flechas, escudos e facas que parecem serem feitos de uma aura verde, criar raios e portais com a ajuda dos espíritos aos quais ele segue fielmente, um meio de honrar os indígenas mortos, de sua tribo e família, vítimias de Shao Kahn.

22 Fixing NightWolf class NightWolf extends Lutador{ public NightWolf(){
comportamentoAtirador = new AtirarComArcoEFlecha(); comportamentoBruxo = new LancarRaio(); } Padrões de Projeto - Strategy Aluno: Mas, professor, você não disse pra gente que nós deveríamos programar para uma superclasse? Aluno: O construtor está apontando para implementações, ou seja, para classes concretas... Isso não seria errado? Professor: Mais adiante aprenderemos alguns padrões para manter o nosso princípio de apenas programar para Superclasses. Professor: Por enquanto, percebam que nós já ganhamos bastante flexibilidade, inclusive, nós podemos mudar o comportamento de cada lutador em tempo de execução através de métodos setters! Professor: Isso, é inclusive, bem interessante, quando formos implementar o Shang Tsung, que é um player realmente “polimórfico”. 

23 Questionamentos Aluno: Mas, professor, você não disse pra gente que nós deveríamos programar para uma superclasse? Aluno: O construtor está apontando para implementações, ou seja, para classes concretas... Isso não seria errado? Professor: Mais adiante aprenderemos alguns padrões para manter o nosso princípio de apenas programar para Superclasses. Professor: Por enquanto, percebam que nós já ganhamos bastante flexibilidade, inclusive, nós podemos mudar o comportamento de cada lutador em tempo de execução através de métodos setters! Padrões de Projeto - Strategy Professor: Isso, é inclusive, bem interessante, quando formos implementar o Shang Tsung, que é um player realmente “polimórfico”.  A powerful, deadly sorcerer and a primary villain in the Mortal Kombat franchise, Shang Tsung is a shapeshifter who needs to consume souls in order to sustain his health and life. In theMortal Kombat series, he is the epitome of cunning and decadence, as symbolized by his preference for lavish parties, grand palaces, and stylish clothing. Unlike the crude Shao Kahn, this bombast is a facade, disguising Tsung's true intellectual and mental sophistication. His nemesis is Liu Kang, but throughout his unnatural lifespan, he has earned the hatred of many others, including Kung Lao and Kenshi.

24 E por falar em Padrões de Projetos...
Você acaba de aplicar seu primeiro padrão de projeto: o padrão STRATEGY. Com esse padrão, sempre que novos lutadores precisarem ser implementados e novos comportamentos surgirem, o nosso jogo estará pronto para qualquer alteração. O padrão STRATEGY define uma família de algoritmos, encapsula cada um deles e os torna polimórficos. Cada família de algoritmos contém diferentes estratégias para execução, que podem variar dependendo dos clientes que a utilizarem. Padrões de Projeto - Strategy

25 Para casa 1 Adicione à classe Lutador uma variável chamada “Vida”;
Pode ser um int com valor máximo 100; Considere os seguintes danos para os seguintes ataques: Tiro com arma de fogo: -5 Tiro com flecha: -4 Bola de fogo (magia): -10 Bola de gelo (magia): -5 Raio (magia): -10 Soco: -3 Chute: -3 Crie um main onde os lutadores duelam até a morte! Padrões de Projeto - Strategy Gabarito em Strategy.zip.

26 Para casa 2 Já que o gabarito da atividade anterior foi dado, experimente criar: Novos lutadores: só estão criados nightwolf e subzero, você poderia criar mais 2 lutadores e fazer seu próprio duelo; Minha sugestão seria criar o KungLao e o ShangTsun. Para o ShangTsung, faça ele mudar de personagem ao longo do jogo. Novos tipos de comportamento: que tal criar o ComportamentoLancarObjeto? KungLao lança seu chapéu; Nightwolf também lança um machado. Perguntas Reflita o quanto o padrão Strategy lhe ajudou a executar o “polimorfismo” de Shang Tsung... Foi fácil ou difícil implementar essa funcionalidade com o novo padrão aprendido? Por que? Foi fácil ou difícil criar um novo comportamento (laçar objetos) para os lutadores? Por que? Padrões de Projeto - Strategy

27 Para casa 3 Chega de Mortal Kombat... Quer entender melhor ainda esse padrão? Pratique um pouco mais... Implemente o seu próprio jogo! Sugiro que implementem o Street Fighter... Era muito legal.. Concordam? Não se esqueçam de me mostrar o resultado!  Padrões de Projeto - Strategy “Só se conhece o que se pratica.” - Barão de Montesquieu

28 Referências O capítulo 1 do livro “Padrões de Projeto – Use a Cabeça!”; O Mega Drive e a fita cartucho de Mortal Kombat III que tive quando criança foram grandes referências para essa aula.  Padrões de Projeto - Strategy


Carregar ppt "Padrões de Projeto Aula 3 – Padrão Strategy."

Apresentações semelhantes


Anúncios Google