Bỏ từ khóa else trong hàm if. Có nên không?

0
Dịch vụ dạy kèm gia sư lập trình

Trong số các câu lệnh, có lẽ hàm if-else là phổ biến nhất, có mặt trong hầu hết các ngôn ngữ lập trình. Nếu mới học lập trình, bạn sẽ sử dụng nó một cách rất thoải mái. Nhưng khi đã có kinh nghiệm thực chiến, với những dự án yêu cầu khắt khe, bạn tự nhiên dần từ bỏ thói quen dùng từ khóa else. Tại sao ư?

Mình đã từng gặp một bug siêu to khổng lồ, chỉ vì lạm dụng từ khóa else. Đây là “giọt nước tràn ly” để mình dần từ bỏ từ khóa else trong cách viết code.

🔥 Đọc thêm kinh nghiệm lập trình khác:

Bạn có thấy mình vô lý không? Cứ bình tĩnh, mình sẽ giải thích.

Tại sao không nên dùng từ khóa else?

Theo như ý nghĩa của khóa else: “nếu A là cái này, nếu không A thì cái kia”. Điều này luôn đúng nếu thế giới chỉ là hệ nhị phân – không gian vấn đề chỉ có 2 trường hợp.

Nhưng thực tế cuộc sống đâu chỉ có vậy. Không gian bài toán phủ định nó lớn hơn rất nhiều và cũng khó lường không kém.

Để tránh rắc rối với hàm if/ if else, chúng ta chỉ nên sử dụng câu lệnh if. Dành thời gian phân tích để đảm bảo tiêu chí đầu vào cho nhóm điều kiện if loại trừ lẫn nhau để câu trả lời không phụ thuộc vào thứ tự thực thi.

Dưới đây là một số giải pháp để loại trừ câu lệnh else:

  • Đưa ra một vài điều kiện chính để kiểm tra với câu lệnh if
  • Liệt kê toàn bộ điều kiện, yêu cầu xử lý dữ liệu trong hàm if trước khi vào hàm.
  • Sử dụng câu lệnh switch case
  • Sử dụng tính đa hình để xử lý các trường hợp điều kiện, làm cho code rõ ràng hơn giống như State Pattern.

🔥 Cần đọc thêm design pattern: 5 Design Pattern mà developer cần phải biết

Thực hành loại bỏ từ khóa else

Để minh họa cho bài viết, chúng ta cùng xem xét bài toán sau: Một cột đèn giao thông (TrafficLight object) có 3 trạng thái đèn: Xanh, Vàng, Đỏ. Mỗi trạng thái đèn sẽ có quy tắc riêng:

  • Đèn xanh: Phương tiện được phép di chuyển
  • Đèn vàng: Chuẩn bị để dừng
  • Đèn đỏ: Bắt buộc phương tiện dừng lại.

Luồng hoạt động của đèn như sau:

Green (1 minute) → Yellow (10 seconds)→ Red (1 minute)

Nếu bình thường thì chúng ta sẽ viết code xử lý như sau:

const LightState = {
  GREEN: 0,
  YELLOW: 1,
  RED: 2
}

var TrafficLight = function () {

  var count = 0

  // default state = red
  var currentState = 0;

  this.change = function(state) {
    if (count++ >= 10 ) return
    currentState = state
    this.go(currentState)
  }
  this.go = function(state) {
    if (currentState == LightState.GREEN) {
      console.log("Green --> for 1 minute")
      this.change(LightState.YELLOW)
    } 
    else if (currentState == LightState.YELLOW) {
      console.log("Yellow --> for 10 seconds")
      this.change(LightState.RED)
    } else if (currentState == LightState.RED) {
      console.log("Red --> for 1 minute");
      this.change(LightState.GREEN)
    } else {
      throw Error("Invalid State")
    }
  }
  this.start = function() {
    this.change(LightState.GREEN)
  }
}

Với cách viết trên, chúng ta phải sử dụng hàm if có nhiều điều kiện. Mỗi lần xử lý case phủ định, bạn cũng cần phải nghĩ tới cả phủ định của phủ định nữa. Nói chung là lằng nhằng.

Cách đơn giản nhất bỏ câu lệnh else

Chúng ta chỉ đơn giản là bỏ tất cả câu lệnh else và viết lại điều kiện cho hàm if.

this.go = function (currentState) {
    if (currentState == LightState.GREEN) {
      console.log("Green --> for 1 minute")
      this.change(LightState.YELLOW)
      return
      
    }
    if (currentState == LightState.YELLOW) {
      console.log("Yellow --> for 10 seconds")
      this.change(LightState.RED)
      return
    }
    if (currentState == LightState.RED) {
      console.log("Red --> for 1 minute");
      this.change(LightState.GREEN)
      return
    }
    if (currentState != LightState.GREEN && currentState != LightState.RED && currentState != LightState.YELLOW) {
      throw Error("Invalid State")
    }
}

Hoặc sử dụng switch-case statement thay cho câu lệnh if-else. Một switch-case statement nhìn có vẻ gọn gàng, sạch đẹp hơn nhiều khi phải kết hợp nhiều trường hợp điều kiện.

this.go = function (state) {
    switch (state) {
      case LightState.GREEN:
        console.log("Green --> for 1 minute")
        this.change(LightState.YELLOW)
        break
      case LightState.YELLOW:
        console.log("Yellow --> for 10 seconds")
        this.change(LightState.RED)
        break
      case LightState.RED:
        console.log("Red --> for 1 minute");
        this.change(LightState.GREEN)
        break
      default:
        throw Error("Invalid State")
    }
  }

Trên đây là 2 giải pháp thông thường nhất. Nếu muốn nâng cao hơn, mời bạn đến giải pháp tiếp theo, sử dụng State Pattern[1].

Sử dụng State Pattern để lại bỏ câu lệnh if-else

Ở trên, chúng ta đã sử dụng rất nhiều câu lệnh if-else hay switch-case block để xử lý các điều kiện.

State pattern được thiết kế phù hợp với từng ngữ cảnh để xử lý điều kiện.

Nó cho phép đối tượng có nhiều hành vi khác nhau dựa trên trạng thái hiện tại. Bạn có thể định nghĩa state-specific (xác định hành vi cho từng trạng thái cụ thể).

Như trong bài toán trên, chúng ta suy nghĩ về các trạng thái có thể có của đèn giao thông, sau đó tách code sao cho phù hợp.

  • Các thao tác (ví dụ: chuyển trạng thái đèn từ xanh -> vàng -> đỏ) được định nghĩa cho đèn giao thông sẽ được delegate cho state object hiện tại.
  • States tự kích hoạt state transitions –  tự kích hoạt chuyển trạng thái.

Và đây là kết quả cuối cùng:

var TrafficLight = function () {

    var count = 0

    // default state = green
    var currentState = new Green(this);

    this.change = function (state) {
        // limits number of changes
        if (count++ >= 10) return;
        currentState = state;
        currentState.go();
    }
    this.start = function () {
        currentState.go();
    }
}

var Red = function (light) {
    this.light = light

    this.go = function () {
        console.log(("Red --> for 1 minute"))
        light.change(new Green(light));
    }
}

var Yellow = function (light) {
    this.light = light;
 
    this.go = function () {
        console.log("Yellow --> for 10 seconds")
        light.change(new Red(light));
    }
};

var Green = function (light) {
    this.light = light;
 
    this.go = function () {
        console.log("Green --> for 1 minute");
        light.change(new Yellow(light));
    }
};

Bạn thấy đấy, với cách viết code, chúng ta không hề sử dụng tới câu lệnh if-else. Chúng ta chỉ quan tâm tới trạng thái của đèn là gì mà xử lý tương ứng. Nhìn code rất đẹp đúng không?

Mình hi vọng, bài viết này sẽ có ích cho dự án của bạn. Để lại cảm nhận của bạn ở dưới bình luận nhé.

Tài liệu tham khảo:

  • [1] Erich Gamma & Richard Helm & Ralph Johnson & John Vlissides. Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley Professional, 1994
  • Javascript in Plain English
Dịch vụ phát triển ứng dụng mobile giá rẻ - chất lượng
Bài trước[Android] Tạo custom Dialog với hiệu ứng Circular Reveal
Bài tiếp theoRealm database trong Android – Giải pháp hoàn hảo thay thế SQLite
Sơn Dương
Tên đầy đủ là Dương Anh Sơn. Tốt nghiệp ĐH Bách Khoa Hà Nội. Mình bắt đầu nghiệp coder khi mà ra trường chẳng xin được việc đúng chuyên ngành. Mình tin rằng chỉ có chia sẻ kiến thức mới là cách học tập nhanh nhất. Các bạn góp ý bài viết của mình bằng cách comment bên dưới nhé !

Bình luận. Cùng nhau thảo luận nhé!

avatar
  Theo dõi bình luận  
Thông báo