Object Oriented Programming
-
Upload
marco-antonio-filho -
Category
Documents
-
view
149 -
download
0
description
Transcript of Object Oriented Programming
LICENÇA
MARCO ANTONIO FILHO
COORDENADOR DE TI INPACT.ME
UM POUCO DE RUBY
10 COISAS SOBRE RUBY # 1. Tudo eh um objeto 5.times { print "Hello World!" } # 2. Blocos sample_array.each { |element| print element } # 3. Retorno de funcao implicito def sum(a,b) a + b end # 4. Tudo eh aberto class Fixnum def previous self – 1 end end 6.previous # 5. Operadores unarios. Nao ha ++, -‐-‐; Use +=
10 COISAS SOBRE RUBY # 6. Atribuicao paralela a, b = b, a # 7. Cada string é um objeto print "hello".object_id print "hello".object_id # Um novo objeto # 8. Verdadeiro e falso em Ruby if 0 print "Hello World" end # 9. Suporte a faixa de numeros e expressoes regulares de forma nativa (1..10).each { print "Hello World" } # 10. Indicadores de metodo class Woman def loves?(thing) thing == "chocolate" ? true : false end end
APLICAÇÃO SIMPLES puts "Welcome! What do you want to be?" # Imprime na tela choice = gets.strip # Lê do teclado e remove \n if choice == "Knight" # Comparacao em if puts "Then a princess you must save" elsif choice == "Wizard" # Else if com condicao puts "Then a book you must find" else puts "Just stay at home" end puts "What is your strength?" choice = gets.to_i # Le do teclado e converte para int damage = choice.times.collect do
rand(6) + 1 end.inject(:+) puts "You did #{damage} damage" # String com interpolacao
EXERCÍCIO OBJETIVO
Criar o primeiro programa em Ruby: Calculadora de dano.
MÉTODO
§ Crie arquivo calculator.rb;
§ Leia do teclado a força e depois leia a armadura;
§ Para cada unidade de força jogue um dado de seis lados. A soma é o valor de ataque;
§ Para cada unidade de armadura jogue um dado de seis lados. A soma é o valor de defesa;
§ A subtração do ataque com a defesa é o dano total. Apresente este resultado;
§ Para executar o programa no terminal execute ruby calculator.rb
15 MIN
UM POUCO DE ARQUITETURA
MVC
MODELS - Representam os modelos do sistema CONTROLLERS - Representam as ações do sistema VIEWS - Interfaces resultantes de ações ASSETS - Arquivos auxiliares (images, js, css) BIN - Arquivo binários LIB - Módulos auxiliares
INICIALIZAÇÃO # bin/nome_da_aplicacao.rb libs = [ File.expand_path('../../lib', __FILE__), File.expand_path('../../app', __FILE__) ] $LOAD_PATH.unshift *Dir.glob(libs) require "nome_da_aplicacao"
# lib/nome_da_aplicacao.rb # inicialmente vazio
$ ruby bin/nome_da_aplicacao.rb
Para executar faça uso do seguinte comando no terminal:
EXERCÍCIO OBJETIVO
Construir a sua arquitetura
MÉTODO
§ A partir dos conceitos dados monte a sua arquitetura MVC;
§ Crie o arquivo de inicialização da aplicação;
§ Crie o arquivo de gerenciamento de dependências;
§ Para testar coloque um comando para escrita na tela no arquivo de dependências;
§ Execute;
§ Se funciona, apague a linha usada o comando de escrita na tela;
5 MIN
BATALHA DE CONCEITOS
CONCEITOS DE OO Classe
Atributos
Métodos
Character name str skill
attack() defend()
string int int
Character #2
name str skill
attack() defend()
James 3 2
Character #1 name str skill
attack() defend()
Marc 2 4
Character #3 name str skill
attack() defend()
Leon 1 3
INSTÂNCIAS
CLASSES Classe
Atributos
Métodos
Dungeon name type
string string
Dungeon #2
name type
Garlia Prison
Dungeon #1 name type
Syrus Castle
INSTÂNCIAS
CLASSES ESTÁTICAS Die
sides int
self.roll()
Não pode ser instanciada! Só há um dado no jogo
MÓDULOS EM RUBY # lib/save_the_princess/die.rb class Die @@sides = 6 # Roll the die # You can change the amount of sides. Default is 6. def self.roll(sides = @@sides) rand(6) + 1 end end
# lib/save_the_princess.rb require "save_the_princess/die.rb"
Adicionar classe à lista de dependências
INTERACTIVE RUBY
$ irb -‐Ibin -‐rsave_the_princess > Die.roll => 4
Ambiente interativo para desenvolvimento e teste de comandos em Ruby
CLASSES EM RUBY # app/models/character.rb class Character # Character profile attributes attr_accessor :name attr_accessor :strength, :skill, :resistance, :armor, :fire_power # The sum of the amount of strength die rolls. def attack strength.times.collect do Die.roll end.inject(:+) end # The sum of the amount of armor die rolls. def defend armor.times.collect do Die.roll end.inject(:+) end end
LEMBRE-SE DE ADICIONAR A DEPENDÊNCIA!
INTERACTIVE RUBY
$ irb -‐Ibin -‐rsave_the_princess > character = Character.new > character.name = "Marc" > character.name => "Marc" > character.strength = 3 > character.attack => 15 > character.defend NoMethodError: undefined method `times' for nil:NilClass
# lib/save_the_princess.rb require "save_the_princess/die.rb" require "models/character.rb"
LEMBRETE
EXERCÍCIO OBJETIVO
Escrever as classes Die e Character;
MÉTODO
§ Na classe Die deve existir o método self.roll representando um jogar de dados;
§ Na classe Character defina os seus atributos e os métodos attack e defend;
§ Execute no IRB;
§ Em Character adicione um método para calcular a vida do personagem:
§ O método calculate_health_points é baseado na resistência do usuário;
§ É necessário guardar a vida em um atributo chamado max_health_points;
30 MIN
CONSTRUTORES class Character ... attr_accessor :max_health_points # Character constructor. Sets the attributes default values. def initialize(params = {}) @name = params[:name] || "" @strength = params[:strength] || 0 @skill = params[:skill] || 0 @resistance = params[:resistance] || 0 @armor = params[:armor] || 0 @fire_power = params[:fire_power] || 0 calculate_max_health_points end end
self.name = @name = ...
INTERACTIVE RUBY
$ irb -‐Ibin -‐rsave_the_princess > c = Character.new name: "Marc", strength: 2, skill: 4, resistance: 2 => #<Character:0x007fcf2210f3d0 @name="Marc", @strength=2, @skill=4, @resistance=2, @armor=0, @fire_power=0, @max_health_points=12> > c.name => "Marc" > c.max_health_points = 200 > c.max_health_points 200
HERANÇA Character
name str skill
attack() defend()
string int int
Knight
slash()
Priest
heal()
Archer
fire_arrow()
SUB-CLASSES
INSTÂNCIAS
HERANÇA class Knight < Character # Do an attack with a bonus of 3 def slash attack + 3 end end
$ irb -‐Ibin -‐rsave_the_princess > k = Knight.new name: "Marc", strength: 2, skill: 4, resistance: 2 => #<Knight:0x007ffcf280e750 @name="Marc", @strength=2, @skill=4, @resistance=2, @armor=0, @fire_power=0, @max_health_points=8> > k.slash => 9 > c = Character.new name: "James", strength: 3, skill: 2, resistance: 1 => #<Character:0x007f93a30f90e0 @name="James", @strength=3, @skill=2, @resistance=1, @armor=0, @fire_power=0, @max_health_points=3> > c.slash NoMethodError: undefined method `slash' for #<Character:0x007f93a30f90e0>
EXERCÍCIO OBJETIVO
Escrever a classe Dungeon e as classes filhas de Character;
MÉTODO
§ Com o que já aprendeu construa a classe Dungeon, com seu nome e tipo;
§ Combine com o colega ao lado quais classes filhas cada um vai escrever;
§ Escreva as classes e partilhe com o seu colega;
§ No arquivo de inicialização carregue um array de personagens e masmorras para disponibilizar para a aplicação, sem ter a necessidade de criar toda vez que é inicializada.
50 MIN
# bin/save_the_princess.rb @characters = [Character.new ..., ...]
MODIFICADORES DE ACESSO class Character ... attr_reader :max_health_points private # Calculate max health based on resistance. def calculate_max_health_points ... end end
> c = Character.new name: "James", strength: 3, skill: 2, resistance: 1 => #<Character> > c.max_health_points = 1000 NoMethodError: undefined method `max_health_points=' for #<Character> > c.calculate_max_health_points NoMethodError: private method `calculate_max_health_points' called for #<Character> > c.max_health_points 5
QUE A BATALHA COMECE!!!
Battle
...
start() start_round() start_turn()
COESÃO E ACOPLAMENTO
fazendo mais do que deveria == baixa coesão
Battle
...
start()
COESÃO E ACOPLAMENTO
muitas dependências == alto acoplamento
Round
...
start()
Turn
...
start()
Battle
...
start()
ALTA COESÃO E BAIXO ACOPLAMENTO
Round
...
start() Turn
...
start()
Importante! Ruby não possui interfaces. É necessário implementar uma solução.
OBJETIVO Classe deve fazer o que propõe Classe deve possuir o mínimo de relacionamento possível
A BATALHA
REGRAS
1. Iniciativa: Joga-se um dado. Aquele que obtiver maior valor ataca primeiro. Caso igual joga-se de novo;
2. Ataque: Caso seja um ataque normal, seguir para 3, senão fazer um teste de habilidade;
3. Dano: A soma resultante de lances de dados equivalente à força ou poder de fogo;
4. Defesa: A soma resultante de lances de dados equivalente à defesa. Valor do dano é subtraído;
5. Pontos de vida: O dano que ultrapassa a soma da Armadura é subtraído de seus pontos de vida;
6. Retaliação: Se ainda estiver vivo, o lutador que foi atacado revida e os passos 2 a 4 são repetidos;
CLASSES DE COMBATE # app/models/battle.rb class Battle attr_accessor :challenger, :opponent # Armazena os combatentes def initialize(params = {}) end # Instancia rodadas até que # os pontos de vida de um # pesonagem chegue a zero. # Recupera os combatentes. def start end end
# app/models/battle.rb class Battle::Round attr_accessor :challenger, :opponent # Armazena os combatentes def initialize(params = {}) end # Verifica quem terá a # iniciativa e istancia # turnos. def start end end
# app/models/battle.rb class Battle::Round::Turn attr_accessor :attacker, :defender # Armazena os combatentes def initialize(params = {}) end # Calcula o dano feito em # combate. def start end end
EXERCÍCIO OBJETIVO
Escrever a classe Battle e todas as suas dependências;
MÉTODO
§ Desenvolva as classes Turn, Round e Battle nesta ordem;
30 MIN
EXERCÍCIO OBJETIVO
Adicionar class Team. Uma dungeon pode ter vários times;
MÉTODO § Desenvolver uma classe Team que tem um nome e um vetor de Characters;
§ Adicione ao método initialize da Dungeon para receber times de oponentes como parâmetro;
§ Crie um método visit para Team que receba uma Dungeon como parâmetro;
§ Nesse método os oponentes presentes naquela dungeon devem ser enfrentados;
§ O vencedor será a batalha entre o primeiro do time 1 luta contra o primeiro do time 2;
2 HORAS
BOAS PRÁTICAS
DON’T REPEAT YOURSELF (DRY) # app/models/character.rb class Character ... # The sum of the amount of strength die rolls. def attack [strength, fire_power].max.times.collect do Die.roll end.inject(:+) end # The sum of the amount of armor die rolls. def defend armor.times.collect do Die.roll end.inject(:+) end end
DON’T REPEAT YOURSELF (DRY) # app/models/character.rb class Character ... # The sum of the amount of strength die rolls. def attack roll_die_for [strength, fire_power].max end # The sum of the amount of armor die rolls. def defend roll_die_for armor end protected def roll_die_for(attribute) attribute.times.map{ Die.roll }.inject(:+) end end
Character
CONVENTION OVER CONFIGURATION character.rb characters
Nome de arquivo Nome de classe Nome de tabela
§ ClassesEmCamelCase; § variaveis_e_funcoes_sempre_minusculas; § CONSTANTES_SEMPRE_MAIUSUCLAS;
DOCUMENTE RDOC
Documentar a aplicação em Ruby é simples:
$ rdoc -‐-‐all Parsing sources... 100% [12/12] UTF-‐8 Generating Darkfish format into /Users/marco/Projects/Rails/save-‐the-‐princess/doc... Files: 12 Classes: 10 (10 undocumented) Modules: 1 ( 1 undocumented) Constants: 1 ( 1 undocumented) Attributes: 21 (20 undocumented) Methods: 38 (33 undocumented) Total: 71 (65 undocumented) 8.45% documented Elapsed: 0.8s
EXERCÍCIO OBJETIVO
Refatorar a classe Battle e seus sub-módulos;
MÉTODO § Simplificar as funções das classes criando classes mais específicas;
§ Garantir que a classe funciona da mesma forma;
§ Gere a documentação do seu projeto com RDoc;
1 HORA
EXERCÍCIO OBJETIVO
Classe Battle deve prover batalhas entre times;
MÉTODO § Alterar a classe Battle para receber dois times (ao invés de characters);
§ Para cada personagem no time desafiante (challenger) deve ser feita uma rodada escolhendo um inimigo aleatório, assim como, o time desafiado (opponent) deve ter uma rodada para cada integrante escolhendo um adversário aleatório;
§ Tente fazer o mínimo de alterações nas classes Turn e Round;
4 HORAS
# Dica @challengers.each do |challenger| Round.new challenger: challenger, opponent: @opponents.shuffle[0] end
DÚVIDAS
? ? ?
?
?
? ?
? ?
?
? ?