Lab4 Luty Rodrigues

aluno: Luty Rodrigues Ribeiro
ano/sem: 2008/2o.
data do laboratório (num. da semana) : 03/11/2008 (6)

Introdução

Neste laboratório, começamos a lidar com a linguagem Ruby, que também uma linguagem orientada a objetos (assim como Java), mas é uma linguagem do tipo dinâmica. Este laboratório visa, principalmente, permitir o contato inicial com Ruby e mostrar diferenças entre Ruby e Java, já que teremos que fazer uma mesma tarefa (no caso, a tarefa do lab2) nas duas linguagens.

Desenvolvimento

Começamos portando as classes do lab2, com algumas diferenças. Para os tipos de comportamento (SafoPreguicoso, Esforcado, Pemba,…), não precisaremos da classe Comportamento, já que não precisamos declarar os tipos das variáveis. Poderíamos implementar a classe comportamento como superclasse dos vários tipos de comportamento, a fim de aproveitar, pelo menos, a herança do construtor, mas não faremos isso para esta situação. Algo semelhante ocorre para as classes AlunoITA, AlunoUSP e AlunoUnicamp. Neste caso, implementamos a classe Aluno como superclasse das três citadas, aproveitamos os métodos e variáveis da classe Aluno, e apenas sobreescrevemos, em cada subclasse, o método "setComportamento", que foi alterado para comportamento=() (que é a forma de escrever um setter em Ruby).
Abaixo, segue os códigos das classes, no arquivo minhas_classes.rb:

class Aluno  
  attr_writer :comportamento  
  attr_reader :nome, :conhecimento
 
  def initialize(str, queue) 
    @nome, @queue, @conhecimento, @comportamento = str, queue, 0, Esforcado.new(self)
  end
 
  def faz_e_entrega_relatorio 
    qualidade = (2*@comportamento.dedicacao + @comportamento.inteligencia)/3
    originalidade = (@comportamento.dedicacao() + 2*@comportamento.inteligencia())/3
    relatorio = Relatorio.new(qualidade, originalidade, self)
    @queue.queue(relatorio)    
    @conhecimento += 1
  end
 
  def inteligencia 
    @comportamento.inteligencia
  end
 
  def dedicacao 
    @comportamento.dedicacao
  end
end
 
class AlunoITA < Aluno
  def comportamento=(comport)
    raise(Exception.new) if comport.class==Burro
    @comportamento=comport
  end
 
end
 
class AlunoUSP < Aluno
  def comportamento=(comport)
    raise(Exception.new)  if (comport.class==Summa || comport.class==SafoPreguicoso)
    @comportamento=comport
  end
 
end
 
class AlunoUnicamp < Aluno
  def comportamento=(comport)
    raise(Exception.new)  if (comport.class==Summa || comport.class==SafoPreguicoso)
    @comportamento=(comport)
  end
 
end
 
class Burro
  def initialize(aluno)
    @aluno, @inteligencia, @dedicacao = aluno, 0.0, 0.0
  end  
  attr_reader :inteligencia, :dedicacao
end
 
class Imprevisivel
  def initialize(aluno)
    @aluno = aluno
  end
 
  def inteligencia
    rand
  end
 
  def dedicacao
    rand
  end
end
 
class Pemba
  def initialize(aluno)
    @aluno = aluno
  end
  def inteligencia
    0.5*rand
  end
  def dedicacao
    0.5*rand
  end
end
 
class Esforcado
  def initialize(aluno)
    @aluno, @inteligencia, @dedicacao = aluno, 0.5, 1.0
  end
  attr_reader :inteligencia, :dedicacao
end
 
class Summa
  def initialize(aluno)
    @aluno, @inteligencia, @dedicacao = aluno, 1.0, 1.0
  end 
  attr_reader :inteligencia, :dedicacao
end
 
class SafoPreguicoso
  def initialize(aluno)
    @aluno, @inteligencia = aluno, 1.0
  end
  attr_reader :inteligencia
  def dedicacao
    0.5*rand
  end
end
 
class RelaQueue
  def initialize
    @queue = Queue.new
  end
 
  def queue(relatorio)
    @queue << relatorio
  end
 
  def dequeue
    @queue.pop
  end
 
  def size
    @queue.length
  end
end
 
class Professor
  def initialize(queue)
    @queue = queue
  end
 
  def corrigir_relatorios
    n = @queue.size
    while (n>0)
      aux = @queue.dequeue
      puts ("#{aux.aluno.nome}"+": "+"#{corrige_relatorio(aux)}\n")
      n = @queue.size
    end    
  end
 
  private
  def corrige_relatorio(rela)
    nota = 10*(rela.qualidade + rela.originalidade + rand)/3
  end  
end
 
class Relatorio
  def initialize(qualidade, originalidade, aluno)
    @qualidade, @originalidade, @aluno = qualidade, originalidade, aluno
  end
  attr_reader :qualidade, :originalidade, :aluno
end

Observando cada classe, podemos notar uma redução significativa de linhas de código, propiciada pelos atalhos fornecidos pela linguagem (como atribuição em paralelo, attr_acessor), pela tipagem dinâmica (evitando uso de interfaces, classes abstratas como intermediários), etc.
Em seguida, temos o arquivo testes.rb, contendo a classe de teste dada como exemplo e uma outra classe de teste contendo os testes correspondentes do lab2, devidamente reescritos em Ruby:

require 'minhas_classes' #carregue o código da sua aplicação aqui
require 'test/unit'
#este é só um exemplo, não é toda a classe de testes!
class TestInteressante < Test::Unit::TestCase
  def test_meu_teste
    queue = RelaQueue.new
    aluno = AlunoITA.new("John Smith", queue)
    aluno.comportamento = SafoPreguicoso.new(aluno)
    assert_equal(1.0, aluno.inteligencia(), 0.01)
    assert(aluno.dedicacao() < 0.5)
    assert_raise(Exception) { aluno.comportamento = Burro.new(aluno) }  # passa um bloco de código
                                                                                            #que é executado e deve gerar exceção
  end
end
 
class Teste < Test::Unit::TestCase
  def test_funciona_como_o_lab1
    queue = RelaQueue.new
    prof = Professor.new(queue)
 
    aluno1 = Aluno.new("John Smith", queue)
    aluno2 = Aluno.new("Mark Smith", queue)
    aluno3 = Aluno.new("Joseph Smith", queue)
    aluno4 = Aluno.new("Robert Smith", queue)
 
    begin
      aluno3.comportamento = (SafoPreguicoso.new(aluno3))
      aluno4.comportamento = (SafoPreguicoso.new(aluno4))
    rescue Exception=> e
      fail "Não deveria lançar erro!"
    end
 
    #teste de aluno_esforçado
    assert_equal(0.5, aluno1.inteligencia , 0.01)
    assert_equal(1, aluno1.dedicacao, 0.01)
 
    #teste de aluno_safo
    assert_equal(1.0, aluno3.inteligencia, 0.01)
    assert(aluno3.dedicacao != aluno3.dedicacao)
    assert(aluno3.dedicacao < 0.5)
 
    #alunos começam a fazer os relas
    aluno1.faz_e_entrega_relatorio
 
    #roubamos o relatório do primeiro aluno para investigá-lo
    rela1 = queue.dequeue
    assert_equal(aluno1, rela1.aluno)
    assert(rela1.aluno.nome == "John Smith")
    assert(rela1.qualidade < 0.9)
    assert(rela1.qualidade > 0.8)
    assert(rela1.originalidade < 0.7)
    assert(rela1.originalidade > 0.6)
 
    #os outros continuam a fazer os relas
    aluno2.faz_e_entrega_relatorio
    aluno3.faz_e_entrega_relatorio
    aluno4.faz_e_entrega_relatorio
 
    #deve exibir a correção dos relas dos alunos aluno2, aluno3 e aluno4, nesta ordem
    #pois "roubamos" o relatório do aluno1
    prof.corrigir_relatorios
  end
 
  def test_os_comportamentos_funcionam_como_especificado
    queue = RelaQueue.new
    aluno1 = Aluno.new("John", queue)
    summa = Summa.new(aluno1)
    pemba = Pemba.new(aluno1)
    imprevisivel = Imprevisivel.new(aluno1)
    safo = SafoPreguicoso.new(aluno1)
    esforcado = Esforcado.new(aluno1)
    burro = Burro.new(aluno1)
 
    #teste de esforçado
    assert_equal(0.5, esforcado.inteligencia, 0.01)
    assert_equal(1, esforcado.dedicacao, 0.01)
 
    #teste de burro
    assert_equal(0.0, burro.inteligencia, 0.01)
    assert_equal(0.0, burro.dedicacao, 0.01)
 
    #teste de summa
    assert_equal(1.0, summa.inteligencia, 0.01)
    assert_equal(1.0, summa.dedicacao, 0.01)
 
    #teste de safo
    assert_equal(1.0, safo.inteligencia, 0.01)
    assert(safo.dedicacao != safo.dedicacao)
    assert(safo.dedicacao() < 0.5)
 
    #teste de imprevisivel
    assert(imprevisivel.inteligencia != imprevisivel.inteligencia)
    assert(imprevisivel.inteligencia < 1.0)
    assert(imprevisivel.dedicacao != imprevisivel.dedicacao);
    assert(imprevisivel.dedicacao() < 1.0)
 
    #teste de pemba
    assert(pemba.inteligencia != pemba.inteligencia)
    assert(pemba.inteligencia < 0.5)
    assert(pemba.dedicacao != pemba.dedicacao) 
    assert(pemba.dedicacao < 0.5)
  end
 
  def test_as_subclasses_de_aluno_tem_restricoes
    queue = RelaQueue.new
    alunoITA = AlunoITA.new("John Smith", queue)
    alunoUSP = AlunoUSP.new("Mark Smith", queue)
    alunoUnicamp = AlunoUnicamp.new("Joseph Smith", queue)
 
    begin
      alunoITA.comportamento = SafoPreguicoso.new(alunoITA)
      alunoITA.comportamento = Summa.new(alunoITA)
      alunoUSP.comportamento = Burro.new(alunoUSP)
      alunoUnicamp.comportamento = Burro.new(alunoUnicamp)
    rescue Exception => e
      fail "Não deveria lançar erro!"
    end
 
    begin
      alunoITA.comportamento = Burro.new(alunoITA)
      fail "Deveria lançar erro!"
    rescue Exception => e    
    end
 
    begin
      alunoUSP.comportamento = SafoPreguicoso.new(alunoITA)
      fail "Deveria lançar erro!"
    rescue Exception => e    
    end
 
    begin
      alunoUnicamp.comportamento = Summa.new(alunoITA)
      fail "Deveria lançar erro!"
    rescue Exception => e    
    end
  end
end
 
#Teste de polimorfismo não será necessário para este caso

Abaixo, apresentamos o resultado da execução desta classe de testes pela linha de comando:

lab4-fig01.JPG

Após aprovado nos testes, vamos executar o programa, através do arquivo simulador.rb, partindo novamente da linha de comando:

lab4-fig02.JPG
lab4-fig03.JPG

Se comparamos o resultado obtido acima com o obtido no lab2, a menos da formatação e dos valores numéricos (que dependem de valores gerados aleatoriamente), vemos que os resultados obtidos são praticamente os mesmos. Uma vantagem deste lab4 em relação ao lab2 foi que já havia o conhecimento prévio dos conceitos de orientação a objeto, bem como alguns padrões que foram utilizados, além do fato de já ter o código escrito em Java. Isso permitiu que o código em Ruby fosse gerado bem mais rápido.

Conclusão

Com este laboratório, foi possível se integrar melhor com a linguagem Ruby, bem como perceber algumas diferenças (até vantajosas) de Ruby em relação a Java. Uma vantagem que foi notável, foi que, devido a sua tipagem dinâmica, excluímos a necessidade da classe abstrata na implementação do padrão Strategy. Isso até faz com que esta solução seja de mais fácil compreensão e evita a necessidade de implementações pouco triviais para contornar restrições da linguagem.

Add a New Comment
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License