12/08/2018, 15:37

Boolean as function parameter, how bad it is?

Lúc mới lập trình, mất một thời gian kha khá, tôi "cảm thấy" có gì đó sai sai, nhưng tôi lại không thể diễn đạt được điều gì sai ở nó, hoặc có thể nó chỉ là thành kiến của tôi chăng? Điều đó cụ thể thế này: Một developer định nghĩa một method với một parameter là kiểu boolean , và method đó gọi ...

Lúc mới lập trình, mất một thời gian kha khá, tôi "cảm thấy" có gì đó sai sai, nhưng tôi lại không thể diễn đạt được điều gì sai ở nó, hoặc có thể nó chỉ là thành kiến của tôi chăng? Điều đó cụ thể thế này:

Một developer định nghĩa một method với một parameter là kiểu boolean , và method đó gọi đến các method khác nhau, cuối cùng biến boolean sẽ quyết định hành động nào sẽ được thực hiện tùy vào giá trị của nó.

Hãy lấy một ví dụ cụ thể. Tưởng tượng chúng ta cần đặt vé cho một buổi hòa nhạc, sẽ có 2 loại vé là regularpremium, và bạn sẽ thực hiện một hàm với một boolean parameter để kiểm tra loại vé cần đặt như sau:

class Concert...
      public Booking book (Customer aCustomer, boolean isPremium) {
              if (isPremium) {
                      actionForPremiumCustomer(aCustomer)
              } else {
                      actionForRegularCustomer(aCustomer)
              }
      }

Bạn có thể nhìn thấy rõ ràng ở đây, hàm book sẽ thực hiện những hành động khác nhau tùy thuộc vào giá trị của isPremium. Vâng điều sai sai ở đây chính là nó, có vẻ nó giống như code smell , về lâu dài sẽ dẫn đến tình trạng khó hiểu, không thể bảo trì hay tái sử dụng. Điều cần nói ở đây là nếu hành vi của một function có thể được quyết định bởi giá trị boolean parameter thì nó hoàn toàn có thể chia nhỏ thành những function nhỏ hơn với logic chặc chẽ hơn (cohesive function - độ kết dính hàm). highly cohesive function là gì? :

It's a function that does one thing and one thing only.

Nghĩa là

là một hàm mà nó làm một việc và chỉ duy nhất một việc.

với ví dụ trên, ta có thể tách thành 2 hàm riêng biệt như sau:

class Concert...
      public Booking regularBook(Customer aCustomer) {...}
      public Booking premiumBook(Customer aCustomer) {...}

Việc tách thành những function nhỏ hơn làm ý nghĩa của nó trở nên rõ ràng và dễ hiểu. Thay vì phải nhớ nghĩa của giá trị của cờ boolean trong book("NamNH", false) giờ đây, ta dễ dàng hiểu regularBook("NamNH") .

Trong trường hợp này bạn vẫn có thể sử dụng một enum để thay thế biến boolean:

enum CustomerType {
     PREMIUM, REGULAR;
}
class Concert...
      public Booking book(Customer aCustomer, CustomerType type) {...}

Và lời gọi book("NamNH", CustomerType.PREMIUM) cũng dễ dàng hiểu và sử dụng.

Tuy nhiên, đó là trong trường hợp đơn giản nhất, giả sử rằng logic của tôi đã trở nên phức tạp hơn

class Concert...
 public Booking book (Customer aCustomer, boolean isPremium) {
      lorem().ipsum();
      dolor();
      if(isPremium)
        sitAmet();
      consectetur();
      if(isPremium)
        adipiscing().elit();
      else {
        aenean();
        vitaeTortor().mauris();
      }
      eu.adipiscing();
  }

Trong trường hợp này, rõ ràng thật khó để tách hàm mà không có vài duplicated code giữa 2 hàm regularBook và premiumBook. Vì thế ta sẽ giữ hàm với boolean parameter, nhưng sẽ giấu nó đi bằng từ khóa private:

class Order...
      public Booking regularBook(Customer aCustomer) {
        return hiddenBookImpl(aCustomer, false);
      }
      public Booking premiumBook(Customer aCustomer) {
        return hiddenBookImpl(aCustomer, true);
      }
      private Booking hiddenBookImpl(Customer aCustomer,  boolean isPremium) {...}

Với cách này, bạn đã thực sự giúp người bảo trì, người sử dụng code của bạn tránh những cơn đau đầu nhất có thể             </div>
            
            <div class=

0