Khái niệm về Lối vào đơn, Lối thoát đơn (SESE) xuất phát từ các ngôn ngữ có quản lý tài nguyên rõ ràng , như C và lắp ráp. Trong C, mã như thế này sẽ rò rỉ tài nguyên:
void f()
{
resource res = acquire_resource(); // think malloc()
if( f1(res) )
return; // leaks res
f2(res);
release_resource(res); // think free()
}
Trong các ngôn ngữ như vậy, về cơ bản bạn có ba tùy chọn:
Nhân rộng mã dọn dẹp.
Ừ Sự dư thừa luôn là xấu.
Sử dụng một goto
để nhảy đến mã dọn dẹp.
Điều này đòi hỏi mã dọn dẹp là điều cuối cùng trong hàm. (Và đây là lý do tại sao một số tranh luận goto
có vị trí của nó. Và nó thực sự có - trong C.)
Giới thiệu một biến cục bộ và điều khiển luồng điều khiển thông qua đó.
Điểm bất lợi là dòng điều khiển thao tác thông qua cú pháp (suy nghĩ break
, return
, if
, while
) là dễ dàng hơn để làm theo hơn dòng điều khiển thao tác thông qua các trạng thái của các biến (vì những biến này không có trạng thái khi bạn nhìn vào các thuật toán).
Khi lắp ráp, nó thậm chí còn lạ hơn, bởi vì bạn có thể chuyển đến bất kỳ địa chỉ nào trong hàm khi bạn gọi hàm đó, điều đó có nghĩa là bạn có số lượng điểm nhập gần như không giới hạn cho bất kỳ chức năng nào. (Đôi khi điều này hữu ích. Các thunks như vậy là một kỹ thuật phổ biến để các trình biên dịch thực hiện this
điều chỉnh con trỏ cần thiết để gọi các virtual
hàm trong các kịch bản đa kế thừa trong C ++.)
Khi bạn phải quản lý tài nguyên theo cách thủ công, việc khai thác các tùy chọn nhập hoặc thoát một chức năng ở bất kỳ đâu dẫn đến mã phức tạp hơn và do đó xảy ra lỗi. Do đó, một trường phái tư tưởng đã xuất hiện tuyên truyền SESE, để có được mã sạch hơn và ít lỗi hơn.
Tuy nhiên, khi một ngôn ngữ có các trường hợp ngoại lệ, (hầu như) bất kỳ chức năng nào cũng có thể bị thoát sớm tại (gần như) bất kỳ điểm nào, vì vậy dù sao bạn cũng cần phải cung cấp các điều khoản cho việc hoàn trả sớm. (Tôi nghĩ rằng finally
được sử dụng chủ yếu cho rằng trong Java và using
(khi thực hiện IDisposable
, finally
khác) trong C #, C ++ thay vì sử dụng RAII .) Một khi bạn đã làm điều này, bạn không thể thất bại trong việc làm sạch sau khi mình do một đầu return
tuyên bố, vì vậy những gì có lẽ là lập luận mạnh mẽ nhất ủng hộ SESE đã biến mất.
Điều đó để lại khả năng đọc. Tất nhiên, hàm 200 LoC với nửa tá return
câu lệnh được rắc ngẫu nhiên trên nó không phải là kiểu lập trình tốt và không tạo ra mã có thể đọc được. Nhưng một chức năng như vậy sẽ không dễ hiểu nếu không có những lợi nhuận sớm đó.
Trong các ngôn ngữ mà tài nguyên không hoặc không nên được quản lý thủ công, có rất ít hoặc không có giá trị trong việc tuân thủ quy ước SESE cũ. OTOH, như tôi đã lập luận ở trên, SESE thường làm cho mã phức tạp hơn . Đó là một con khủng long (trừ C) không phù hợp với hầu hết các ngôn ngữ ngày nay. Thay vì giúp sự dễ hiểu của mã, nó cản trở nó.
Tại sao các lập trình viên Java dính vào điều này? Tôi không biết, nhưng từ POV (bên ngoài) của tôi, Java đã lấy rất nhiều quy ước từ C (nơi chúng có ý nghĩa) và áp dụng chúng vào thế giới OO của nó (nơi chúng vô dụng hoặc hoàn toàn xấu), nơi mà bây giờ nó dính vào họ, không có vấn đề gì (Giống như quy ước để xác định tất cả các biến của bạn ở đầu phạm vi.)
Các lập trình viên dính vào tất cả các loại ký hiệu lạ vì lý do phi lý. (Các câu lệnh cấu trúc lồng nhau sâu sắc - "đầu mũi tên" -, trong các ngôn ngữ như Pascal, từng được coi là mã đẹp.) Áp dụng lý luận logic thuần túy cho điều này dường như không thuyết phục được phần lớn trong số chúng đi chệch khỏi cách thiết lập của chúng. Cách tốt nhất để thay đổi thói quen như vậy có lẽ là dạy chúng sớm làm những gì tốt nhất, không phải những gì thông thường. Bạn, là một giáo viên lập trình, có nó trong tay của bạn.:)