Các bài đăng blog bạn trích dẫn vượt quá yêu cầu của nó một chút. FP không loại bỏ sự cần thiết cho các mẫu thiết kế. Thuật ngữ "các mẫu thiết kế" không được sử dụng rộng rãi để mô tả điều tương tự trong các ngôn ngữ FP. Nhưng chúng tồn tại. Các ngôn ngữ chức năng có rất nhiều quy tắc thực hành tốt nhất của biểu mẫu "khi bạn gặp vấn đề X, hãy sử dụng mã trông giống như Y", về cơ bản đó là mẫu thiết kế.
Tuy nhiên, điều chính xác là hầu hết các mẫu thiết kế dành riêng cho OOP đều không liên quan nhiều đến các ngôn ngữ chức năng.
Tôi không nghĩ nên tranh cãi đặc biệt khi nói rằng các mẫu thiết kế nói chung chỉ tồn tại để khắc phục những thiếu sót trong ngôn ngữ. Và nếu một ngôn ngữ khác có thể giải quyết vấn đề tương tự một cách tầm thường, thì ngôn ngữ khác đó sẽ không cần một mẫu thiết kế cho nó. Người dùng ngôn ngữ đó thậm chí có thể không nhận thức được rằng vấn đề tồn tại , bởi vì, đó không phải là vấn đề trong ngôn ngữ đó.
Dưới đây là những gì Gang of Four nói về vấn đề này:
Sự lựa chọn ngôn ngữ lập trình rất quan trọng vì nó ảnh hưởng đến quan điểm của một người. Các mẫu của chúng tôi giả định các tính năng ngôn ngữ cấp độ Smalltalk / C ++ và lựa chọn đó xác định những gì có thể và không thể thực hiện dễ dàng. Nếu chúng tôi giả định các ngôn ngữ thủ tục, chúng tôi có thể đã bao gồm các mẫu thiết kế được gọi là "Kế thừa", "Đóng gói" và "Đa hình". Tương tự, một số mẫu của chúng tôi được hỗ trợ trực tiếp bởi các ngôn ngữ hướng đối tượng ít phổ biến hơn. CLOS có nhiều phương thức, ví dụ, làm giảm nhu cầu về một mẫu như Người truy cập. Trên thực tế, có đủ sự khác biệt giữa Smalltalk và C ++ để có nghĩa là một số mẫu có thể được thể hiện dễ dàng hơn trong một ngôn ngữ so với ngôn ngữ khác. (Xem Iterator chẳng hạn.)
(Trên đây là trích dẫn từ sách Giới thiệu về Mẫu thiết kế, trang 4, đoạn 3)
Các tính năng chính của lập trình chức năng bao gồm các chức năng như các giá trị hạng nhất, currying, các giá trị bất biến, v.v ... Đối với tôi, dường như không rõ ràng rằng các mẫu thiết kế OO đang xấp xỉ bất kỳ tính năng nào trong số đó.
Mẫu lệnh là gì, nếu không phải là xấp xỉ các hàm hạng nhất? :) Trong ngôn ngữ FP, bạn chỉ cần truyền một hàm làm đối số cho hàm khác. Trong ngôn ngữ OOP, bạn phải kết thúc hàm trong một lớp, bạn có thể khởi tạo và sau đó chuyển đối tượng đó sang hàm khác. Hiệu ứng là như nhau, nhưng trong OOP, nó được gọi là mẫu thiết kế và cần nhiều mã hơn. Và mô hình nhà máy trừu tượng là gì, nếu không cà ri? Truyền tham số cho hàm một chút tại một thời điểm, để định cấu hình loại giá trị mà nó tạo ra khi cuối cùng bạn gọi nó.
Vì vậy, có, một số mẫu thiết kế GoF được hiển thị dư thừa trong các ngôn ngữ FP, bởi vì tồn tại các lựa chọn thay thế mạnh hơn và dễ sử dụng hơn.
Nhưng tất nhiên vẫn có những mẫu thiết kế không được giải quyết bằng ngôn ngữ FP. Tương đương FP của một singleton là gì? (Không quan tâm đến một lúc rằng các singletons thường là một mô hình khủng khiếp để sử dụng.)
Và nó hoạt động cả hai cách quá. Như tôi đã nói, FP cũng có các mẫu thiết kế của nó; mọi người thường không nghĩ về họ như vậy.
Nhưng bạn có thể đã chạy qua các đơn nguyên. Chúng là gì, nếu không phải là một mẫu thiết kế để "đối phó với nhà nước toàn cầu"? Đó là một vấn đề rất đơn giản trong các ngôn ngữ OOP mà không có mẫu thiết kế tương đương nào tồn tại ở đó.
Chúng tôi không cần một mẫu thiết kế để "tăng biến tĩnh" hoặc "đọc từ ổ cắm đó", vì đó chỉ là những gì bạn làm .
Nói một đơn nguyên là một mẫu thiết kế là vô lý như nói các số nguyên với các hoạt động thông thường của chúng và phần tử zero là một mẫu thiết kế. Không, một đơn nguyên là một mô hình toán học , không phải là một mẫu thiết kế.
Trong các ngôn ngữ chức năng (thuần túy), các tác dụng phụ và trạng thái có thể thay đổi là không thể, trừ khi bạn làm việc xung quanh nó với "mẫu thiết kế" đơn nguyên hoặc bất kỳ phương pháp nào khác để cho phép điều tương tự.
Ngoài ra, trong các ngôn ngữ chức năng hỗ trợ OOP (như F # và OCaml), đối với tôi, các lập trình viên sử dụng các ngôn ngữ này sẽ sử dụng cùng một mẫu thiết kế có sẵn cho mọi ngôn ngữ OOP khác. Trên thực tế, ngay bây giờ tôi sử dụng F # và OCaml hàng ngày và không có sự khác biệt nổi bật nào giữa các mẫu tôi sử dụng trong các ngôn ngữ này so với các mẫu tôi sử dụng khi tôi viết bằng Java.
Có lẽ bởi vì bạn vẫn đang suy nghĩ bắt buộc? Rất nhiều người, sau khi tiếp xúc với các ngôn ngữ cấp bách trong suốt cuộc đời, đã có một thời gian khó từ bỏ thói quen đó khi họ thử một ngôn ngữ chức năng. (Tôi đã thấy một số nỗ lực khá buồn cười tại F #, trong đó thực sự mọi chức năng chỉ là một chuỗi các câu lệnh 'let', về cơ bản như thể bạn đã lấy một chương trình C và thay thế tất cả các dấu chấm phẩy bằng 'let'. :))
Nhưng một khả năng khác có thể là bạn chưa nhận ra rằng bạn đang giải quyết vấn đề một cách tầm thường sẽ yêu cầu các mẫu thiết kế bằng ngôn ngữ OOP.
Khi bạn sử dụng currying, hoặc chuyển một hàm làm đối số cho một đối số khác, hãy dừng lại và suy nghĩ về cách bạn làm điều đó bằng ngôn ngữ OOP.
Có sự thật nào cho tuyên bố rằng lập trình chức năng loại bỏ sự cần thiết của các mẫu thiết kế OOP?
Vâng. :) Khi bạn làm việc bằng ngôn ngữ FP, bạn không còn cần các mẫu thiết kế dành riêng cho OOP. Nhưng bạn vẫn cần một số mẫu thiết kế chung, như MVC hoặc các công cụ không phải OOP khác và thay vào đó bạn cần một vài "mẫu thiết kế" dành riêng cho FP. Tất cả các ngôn ngữ đều có khuyết điểm của chúng, và các mẫu thiết kế thường là cách chúng ta làm việc xung quanh chúng.
Dù sao, bạn có thể thấy thú vị khi thử dùng các ngôn ngữ FP "sạch" hơn, như ML (sở thích cá nhân của tôi, ít nhất là cho mục đích học tập), hoặc Haskell , nơi bạn không có nạng OOP để quay trở lại khi bạn phải đối mặt với một cái gì đó mới.
Đúng như dự đoán, một số người phản đối định nghĩa của tôi về các mẫu thiết kế là "vá những thiếu sót trong ngôn ngữ", vì vậy đây là lời biện minh của tôi:
Như đã nói, hầu hết các mẫu thiết kế đều dành riêng cho một mô hình lập trình, hoặc đôi khi thậm chí là một ngôn ngữ cụ thể. Thông thường, họ giải quyết các vấn đề chỉ tồn tại trong mô hình đó (xem các đơn vị cho FP, hoặc các nhà máy trừu tượng cho OOP).
Tại sao mô hình nhà máy trừu tượng không tồn tại trong FP? Bởi vì vấn đề nó cố gắng giải quyết không tồn tại ở đó.
Vì vậy, nếu một vấn đề tồn tại trong các ngôn ngữ OOP, không tồn tại trong các ngôn ngữ FP, thì rõ ràng đó là một thiếu sót của các ngôn ngữ OOP. Vấn đề có thể được giải quyết, nhưng ngôn ngữ của bạn không làm như vậy, nhưng đòi hỏi một loạt mã soạn sẵn từ bạn để làm việc xung quanh nó. Lý tưởng nhất, chúng tôi muốn ngôn ngữ lập trình của chúng tôi tạo ra tất cả vấn đề biến mất. Bất kỳ vấn đề nào vẫn còn nguyên tắc là sự thiếu sót của ngôn ngữ. ;)