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

Gỡ rối mã Spaghetti với một thay đổi quan điểm đơn giản

Một mớ hỗn độn khổng lồ của if tuyên bố cứ nhìn chằm chằm vào mặt bạn. Bạn cảm thấy mình nên có thể đơn giản hóa nó, ngoại trừ Logic kinh doanh luôn cản trở.

Ví dụ:giả sử bạn có một nền tảng bán hàng nơi bạn xây dựng Quote s, có nhiều LineItem S. Ngoại trừ, bạn có thể có một báo giá với các mục hàng trùng lặp nếu chúng là quảng cáo , nhưng nếu bạn có nhiều trang web , bạn phải tổng hợp các giá lại với nhau và hiển thị dưới dạng một chi tiết đơn hàng. Ngoài ra, nếu bạn mua một trang web và đã có năm quảng cáo trong báo giá của mình, bạn phải giảm giá cho họ 20% trên trang web.

Tôi có thể nghe thấy tiếng bạn ném máy tính xách tay của mình qua cửa sổ từ đằng này.

Bạn có thể viết một loạt if các câu lệnh để xử lý các quy tắc này:

class Quote
  attr_accessor :line_items
 
  ... 
 
  def add_line_item(line_item)
    if line_item.kind_of?(Ad)
      self.line_items << line_item
    elsif line_item.kind_of?(Website)
      if @line_items.select {|item| item.kind_of?(Ad) }.length >= 5
        # TODO: Put the fractions of a cent into a bank account
        # I have set up
        line_item.price *= 0.8
      end
      existing_website = self.line_items.detect { |item| item.kind_of?(Website) }
      if existing_website
        existing_website.price += line_item.price
      else
        self.line_items << line_item
      end
    end
  end
end

Nhưng tôi nghĩ chúng ta có thể đồng ý rằng điều đó thật khủng khiếp. Làm thế nào bạn có thể gỡ rối một cái gì đó như vậy?

Bạn có thể phân tích phương pháp này thành một loạt các phương pháp nhỏ hơn, nhưng điều đó giống như việc cất tất cả đồ chơi vào tủ để mẹ bạn nghĩ rằng bạn đã dọn dẹp phòng của mình. Và những kind_of? s vẫn sẽ làm phiền tôi rất nhiều.

Nhưng điều gì sẽ xảy ra nếu bạn bắt đầu nhìn thấy những thứ từ mục hàng của quan điểm, thay vì trích dẫn? Nếu thay vì hỏi bạn đang xử lý loại mục hàng nào và thêm nó vào báo giá, bạn vừa nói với chi tiết đơn hàng để thêm chính nó vào báo giá?

Đảo ngược các phương pháp của bạn!

Một trong những cách yêu thích của tôi để cấu trúc lại mã là thử đảo ngược người gọi và người gọi. Dưới đây là một ví dụ, sử dụng mã ở trên:

app / models / quote.rb
class Quote
  ...
  def add_line_item(line_item)
    line_item.add_to_quote(self)
  end
end
app / models / line_item.rb
class Ad < LineItem
  ...
  def add_to_quote(quote)
    quote.line_items << self
  end 
end
app / models / website.rb
class Website < LineItem
  def add_to_quote(quote)
    if quote.line_items.select {|item| item.kind_of?(Ad) }.length >= 5
      # TODO: Put the fractions of a cent into a bank account
      # I have set up
      self.price *= 0.8
    end
    existing_website = quote.line_items.detect { |item| item.kind_of?(Website) }
    if existing_website
      existing_website.price += self.price
    else
	  quote.line_items << self
    end
  end
end

Nó không hoàn hảo. website.rb vẫn cần một rất nhiều trợ giúp về cấu trúc lại và tôi không hài lòng với việc việc đảo ngược các phương thức đã phá vỡ tính đóng gói của line_items như thế nào .

Nhưng bạn đã loại bỏ lớp phức tạp đầu tiên. Bây giờ bạn có thể đặt mã trên LineItem hoặc Quote , tùy thuộc vào nơi nó có ý nghĩa nhất. LineItem các đối tượng có thể sử dụng kế thừa và mixin để xử lý các điểm tương đồng và khác biệt giữa mỗi LineItem lớp con. Ngoài ra, giờ đây việc thêm LineItem mới rất dễ dàng các lớp con mà không làm đầy add_line_item của bạn phương pháp.

Mã của bạn gọn gàng hơn một chút và linh hoạt hơn rất nhiều. Vì vậy, nói chung, tôi gọi đó là một chiến thắng.

Trường hợp bạn có thể không muốn sử dụng mẫu này

Hữu ích như Phương pháp đảo ngược là, có một số lý do khiến bạn có thể không muốn sử dụng mẫu này:

  • Nó có thể phá vỡ tính đóng gói. Bạn có thể phải để lộ các thuộc tính trên Quote đối tượng mà bạn không muốn tiết lộ công khai.

  • Nó có thể tăng khả năng ghép nối. Cả QuoteAd bây giờ cần biết về nhau. Và tùy thuộc vào bao nhiêu họ cần biết về nhau, điều này có thể làm cho mã của bạn nhiều hơn phức tạp.

  • Nó có thể vi phạm Nguyên tắc trách nhiệm duy nhất trên Ad , bởi vì bây giờ Ad có trách nhiệm biết cách thêm chính nó vào Quote .

Bạn thường có thể giải quyết những vấn đề này. Nhưng bạn nên biết về chúng, vì bạn không muốn việc tái cấu trúc để làm cho mã của mình tệ hơn!

Tại sao nó lại là một trong những mục yêu thích của tôi

Ngay cả với những vấn đề đó, đây là một trong những cách tái cấu trúc yêu thích của tôi. Mã tôi viết sau khi sử dụng mẫu này có xu hướng rõ ràng và tự tin hơn.

Nhưng ngay cả khi không, việc sử dụng mẫu này khiến tôi nghĩ về mối quan hệ giữa các đối tượng của mình theo một cách khác. Khi tôi gặp phải vấn đề “tính năng này thật tệ hại, tôi không thể tin rằng mình phải viết đoạn mã khủng khiếp này để xử lý nó”, nó khiến bộ não của tôi bắt đầu tìm ra những cách mới mà tôi có thể giải quyết những vấn đề đó. Nó buộc tôi phải suy nghĩ về cách tôi có thể cấu trúc mã của mình theo cách khác, và điều đó cực kỳ hữu ích.

Hãy thử bằng mã của riêng bạn

Giống như nhiều mẫu yêu thích của tôi, lần đầu tiên tôi biết đến Phương pháp đảo ngược trong Các mẫu phương pháp hay nhất của Smalltalk và nó đã trở thành một công cụ có giá trị kể từ đó.

Lần tới nếu bạn gặp khó khăn khi đối mặt với những đối tượng tương tự có hành vi hơi khác, hãy thử xem! Nếu bạn thích mã mới hơn, hãy giữ nó. Tuy nhiên, ngay cả khi bạn không làm vậy, bạn sẽ phải suy nghĩ về một con đường dẫn bạn đến mã tốt hơn.