Computer >> Máy Tính >  >> Lập trình >> Ruby

Ngừng sử dụng các câu lệnh trường hợp trong Ruby

Bạn đang sử dụng toàn bộ sức mạnh của OOP (Lập trình hướng đối tượng) hay bạn đang bỏ lỡ?

Nếu bạn đang đưa ra quyết định dựa trên loại đối tượng thì bạn đang bỏ lỡ một tính năng OOP quan trọng:tính đa hình.

Quyết định loại thường được thực hiện bên trong các câu lệnh trường hợp (không thân thiện với OO) và trong bài viết này, bạn sẽ học cách viết mã tốt hơn bằng cách loại bỏ chúng.

Kiểm tra các loại

Hãy để tôi bắt đầu bằng cách cho bạn thấy một ví dụ mà chúng tôi không tận dụng tính đa hình.

Chúng tôi muốn triển khai trò chơi “Rock, Paper, Scissors” và chúng tôi đã quyết định có một Game lớp và một lớp cho mọi lần di chuyển có thể.

Để tìm người chiến thắng, chúng tôi sẽ triển khai play phương pháp trên 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 động thái (những động thái khác theo cùng một mô hình):

Trường hợp
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 có thể gọi play phương pháp với hai nước đi và chúng ta sẽ biết liệu nước đi đầu tiên có thắng hay không.

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

Được rồi, điều này đang hoạt động, nhưng chúng ta có thể làm tốt hơn không? Chúng ta có thể loại bỏ trường hợp xấu xí đó không?

Đa hình thay vì kiểm tra kiểu

Đúng! Chúng ta có thể loại bỏ câu lệnh trường hợp kiểm tra kiểu bằng cách sử dụng các nguyên tắc cơ bản của OOP.

Ý tưởng là sử dụng thực tế rằng chúng ta biết lớp hiện tại để hỏi đối tượng chuyển động khác xem nó có thể đánh bại chúng ta hay không.

Và chúng tôi sẽ sử dụng một tên phương thức cụ thể cho lớp của chúng tôi (cho Rock tên phương thức có thể là:do_you_beat_rock? )

Trong Ruby, tính đa hình là khả năng gửi bất kỳ lệnh gọi phương thức nào (còn được gọi là thông điệp, theo cách nói OOP) đến bất kỳ đối tượng nào mà không cần phải kiểm tra lớp của đối tượng. Điều này còn được gọi là "vịt gõ", nhưng tôi không thích thuật ngữ đó 🙂

Trong Java (vui lòng cho tôi một chút…), bạn có một thứ gọi là “giao diện” cho phép bạn buộc một tập hợp các phương thức được thực thi bởi một lớp ở cấp trình biên dịch.

Chúng tôi không có điều đó trong Ruby (có thể là tốt hơn), vì vậy bạn sẽ phải dựa vào thử nghiệm.

Hãy xem một ví dụ mã về cách triển khai mới này trông như thế nào:

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

Lưu ý rằng câu lệnh trường hợp đã biến mất như thế nào. Nó đã được thay thế bằng một lệnh gọi phương thức duy nhất và hai định nghĩa phương thức.

Cập nhật :Như một số độc giả đã nhận xét, tôi không nhận thấy rằng logic bị đảo ngược khi triển khai mẫu này. Một giải pháp được đề xuất bởi Daniel P. Clark là chỉ cần lật thứ tự trong play phương thức thành move2.wins_against?(move1) .

Cái này không sạch hơn nhiều sao? Bạn nghĩ gì?

Thêm một lần di chuyển!

Bây giờ, giả sử bạn muốn thêm một động thái mới. Bạn sẽ phải thay đổi điều gì?

Hãy suy nghĩ về nó trong một phút…

Với cách tiếp cận câu lệnh tình huống, bạn phải thêm một nhánh mới cho mỗi lần di chuyển. Lưu ý rằng bạn "buộc phải" thay đổi một phương pháp hoạt động hoàn hảo để giới thiệu chức năng mới.

Nhưng đó không phải là vấn đề với phiên bản định hướng OOP hơn của chúng tôi. Tất cả những gì chúng ta phải làm là thêm các phương pháp mới. Đây là nguyên tắc đóng / mở (chữ “O” trong SOLID) đang hoạt động.

Một tùy chọn khác có thể là sử dụng lập trình siêu dữ liệu (với method_missing hoặc define_method ).

Tôi có thực sự sử dụng lập trình siêu mẫu cho việc này không?

Có lẽ là không, trừ khi số lần di chuyển thay đổi liên tục hoặc có một số lượng lớn các bước di chuyển.

Phải trả một khoản chi phí để lập trình ẩn dụ, nó không phải là một viên đạn bạc như một số người có thể tin tưởng. Bạn sẽ có hiệu suất giao dịch và khả năng đọc để có thêm một chút linh hoạt.

Kết luận

Trong bài viết này, bạn đã học được rằng bạn nên tránh sử dụng câu lệnh trường hợp để kiểm tra các loại lớp . Thay vào đó, bạn nên tận dụng tính đa hình .

Điều này sẽ giúp bạn tạo mã 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ó. Bây giờ đến lượt bạn thực hiện và thực hiện một số cấu trúc lại 🙂

Btw, điều này không có nghĩa là tôi ủng hộ việc loại bỏ hoàn toàn các câu lệnh tình huống khỏi hộp công cụ của bạn, nhưng bạn nên cảnh giác bất cứ khi nào bạn thấy mình đang viết một câu lệnh. Đảm bảo rằng đó là giải pháp tốt nhất cho vấn đề.

Đừng quên chia sẻ bài viết này nếu bạn muốn tôi tiếp tục viết những bài báo như thế này!