12/08/2018, 15:52

Stop Using Case Statements in Ruby

Đã bao giờ bạn nghĩ mình đã sử dụng hết sức mạnh của OOP hay là bạn đã bỏ lỡ một số tính năng nào đó? Nếu bạn đang viết code và đưa ra các quyết định dựa trên từng loại đối tượng cụ thể thì bạn đang bỏ lỡ một tính năng quan trọng của OOP: polymorphism Checking For Types Đầu tiên tôi sẽ bắt đầu ...

Đã bao giờ bạn nghĩ mình đã sử dụng hết sức mạnh của OOP hay là bạn đã bỏ lỡ một số tính năng nào đó? Nếu bạn đang viết code và đưa ra các quyết định dựa trên từng loại đối tượng cụ thể thì bạn đang bỏ lỡ một tính năng quan trọng của OOP: polymorphism

Checking For Types

Đầu tiên tôi sẽ bắt đầu bằng một ví dụ mà chúng ta không tận dụng tính đa hình. Giả sử chúng ta đang implement “Rock, Paper, Scissors” game. Tôi quyết định có 1 class Game và các class khác cho các loại Rock, Paper, Scissors có trong game. Kiểm tra xem ai là người thắng bằng việc implement method play trong class Game.

class Game
  def self.play(move1, move2)
    return :tie if move1 == move2
 
    move1.wins_against?(move2)
  end
end

Và đây là một trong những hành động, các class Paper, Scissors khác implement tương tự.

class Rock
  def wins_against?(other_move)
    case other_move
    when Paper then false
    when Scissors then true
    end
  end
end

Bây giờ chúng ta chơi game như sau.

p Game.play(Rock.new, Paper.new)
# false

Các implement trên vẫn làm việc được, nhưng chúng ta có thể làm cho nó tốt hơn không?

Polymorphism Instead of Type Checking

Chúng ta có thể sử dụng các nguyên tắc của OOP để thay thế cho các câu lệnh case trong 3 class Rock Paper Scissors.

In Ruby, polymorphism is the ability to send any method calls (also know as messages, in OOP parlance) to any object without having to check the object’s class. This is also known as “duck typing”, but I don’t like that term

Chúng ta sẽ sử dụng method đặc trưng cho lớp cụ thể. Ví dụ class Rock có thể định nghĩa method do_you_beat_rock?

class Rock
  def wins_against?(other_move)
    other_move.do_you_beat_rock?
  end
 
  def do_you_beat_paper?
    false
  end
 
  def do_you_beat_scissors?
    true
  end
end

class Paper
  def wins_against?(other_move)
    other_move.do_you_beat_paper?
  end
 
  def do_you_beat_rock?
    true
  end
 
  def do_you_beat_scissors?
    false
  end
end

class Scissors
  def wins_against?(other_move)
    other_move.do_you_scissors_rock?
  end
 
  def do_you_beat_paper?
    true
  end
 
  def do_you_beat_rock?
    false
  end
end

Các câu lệnh case statement đã được thay thế bằng 1 method gọi và 2 method định nghĩa.

Conclusion

Trong bài viết này bạn đã học được việc tránh sử dụng case statements cho việc kiểm tra loại class. Thay vào đó là tận dụng lợi ích của tính đa hình trong OOP. Điều này sẽ giúp bạn viết code tốt hơn, có thể được mở rộng bằng cách thêm mã mới thay vì thay đổi mã hiện có. Nhưng không có nghĩa là tôi đang ủng hộ để loại bỏ hoàn toàn case statements, bạn nên coi đây là chú ý trong khi viết code, đảm bảo đó là giải pháp tốt nhất để giải quyết vấn đề.

Bài viết được dịch từ:

https://www.blackbytes.info/2017/04/stop-using-case-statements-in-ruby/

0