Có lập trình chức năng thay thế các mẫu thiết kế GoF?


1047

Kể từ khi tôi bắt đầu học F #OCaml vào năm ngoái, tôi đã đọc một số lượng lớn các bài báo khẳng định rằng các mẫu thiết kế (đặc biệt là trong Java) là giải pháp cho các tính năng còn thiếu trong các ngôn ngữ bắt buộc. Một bài báo tôi tìm thấy đưa ra một tuyên bố khá mạnh mẽ :

Hầu hết những người tôi từng gặp đã đọc cuốn sách Mẫu thiết kế của Gang of Four (GoF). Bất kỳ lập trình viên tự tôn trọng nào cũng sẽ nói với bạn rằng cuốn sách là bất khả tri về ngôn ngữ và các mô hình áp dụng cho công nghệ phần mềm nói chung, bất kể bạn sử dụng ngôn ngữ nào. Đây là một yêu sách cao quý. Thật không may, nó là xa sự thật.

Ngôn ngữ chức năng là cực kỳ biểu cảm. Trong một ngôn ngữ chức năng, người ta không cần các mẫu thiết kế vì ngôn ngữ có khả năng rất cao, bạn kết thúc việc lập trình trong các khái niệm loại bỏ tất cả các mẫu thiết kế cùng nhau.

Các tính năng chính của lập trình chức năng (FP) bao gồm các chức năng như giá trị hạng nhất, giá trị cà ri, giá trị không thay đổi, v.v. Tôi dường như không rõ ràng rằng các mẫu thiết kế OO xấp xỉ bất kỳ tính năng nào trong số đó.

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 mỗi 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ó 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? Nếu vậy, bạn có thể đăng hoặc liên kết đến một ví dụ về mẫu thiết kế OOP điển hình và chức năng tương đương của nó không?


18
Bạn có thể xem bài viết của Steve Yegge ( steve-yegge.blogspot.com/2006/03/iêu )
Ralph

27
"cuốn sách là bất khả tri ngôn ngữ và các mẫu áp dụng cho công nghệ phần mềm nói chung" - cần lưu ý rằng cuốn sách không đồng ý với tuyên bố này, theo nghĩa là một số ngôn ngữ không cần diễn đạt một số điều như mẫu thiết kế: "Các mẫu của chúng tôi giả sử Smalltalk / C ++ - các tính năng ngôn ngữ cấp độ và lựa chọn đó xác định những gì có thể và không thể thực hiện dễ dàng [...] 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 (Trang 331). " (trang 4)
Guildenstern

6
Ngoài ra, hãy nhớ rằng nhiều mẫu thiết kế thậm chí không cần thiết trong các ngôn ngữ mệnh lệnh cấp độ đủ cao.
R. Barzell

3
@ R.Barzell Những "ngôn ngữ mệnh lệnh cấp độ đủ cao" là gì? Cảm ơn.
cibercitizen1

5
@ cibercitizen1 ngôn ngữ gõ vịt với sự hỗ trợ cho các chức năng bậc cao hơn và chức năng ẩn danh. Các tính năng này cung cấp phần lớn sức mạnh mà rất nhiều mẫu thiết kế được cung cấp.
R. Barzell

Câu trả lời:


1077

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ữ. ;)


73
Các mẫu thiết kế mô tả các giải pháp chung cho các vấn đề cơ bản. Nhưng đó cũng là những gì ngôn ngữ lập trình và nền tảng làm. Vì vậy, bạn sử dụng các mẫu thiết kế khi ngôn ngữ và nền tảng bạn đang sử dụng không đủ.
yfeldblum

135
S.Lott: Họ mô tả các giải pháp cho các vấn đề tồn tại trong một ngôn ngữ nhất định, vâng. Không có mẫu thiết kế lệnh trong các ngôn ngữ FP, vì vấn đề mà nó cố gắng giải quyết không tồn tại. Điều đó có nghĩa là họ giải quyết các vấn đề mà chính ngôn ngữ không thể giải quyết. Đó là, những thiếu sót trong ngôn ngữ
jalf

38
Các đơn nguyên là một khái niệm toán học, và bạn đang kéo dài nó với phân loại của bạn. Chắc chắn, bạn có thể xem các hàm, đơn sắc, đơn nguyên, ma trận hoặc các khái niệm toán học khác như các mẫu thiết kế, nhưng chúng giống như các thuật toán và cấu trúc dữ liệu ... các khái niệm cơ bản, độc lập với ngôn ngữ.
Alexandru Nedelcu

41
Chắc chắn, các đơn nguyên là một khái niệm toán học, nhưng chúng cũng là một mô hình. "Mô hình FP" của các đơn nguyên có phần khác biệt với khái niệm toán học của các đơn vị. Cái trước là một mẫu được sử dụng để khắc phục một số "hạn chế" nhất định trong các ngôn ngữ FP thuần túy. Sau này là một khái niệm toán học phổ quát.
jalf

69
Lưu ý rằng các đơn nguyên trong Haskell được sử dụng cho những thứ khác ngoài trạng thái có thể thay đổi, ví dụ cho các trường hợp ngoại lệ, tiếp tục, hiểu danh sách, phân tích cú pháp, lập trình không đồng bộ, v.v. Nhưng tất cả những ứng dụng này của các đơn vị có thể được gọi là các mẫu.
JacquesB

152

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?

Lập trình hàm không giống như lập trình hướng đối tượng. Các mẫu thiết kế hướng đối tượng không áp dụng cho lập trình chức năng. Thay vào đó, bạn có các mẫu thiết kế lập trình chức năng.

Đối với lập trình chức năng, bạn sẽ không đọc sách mẫu thiết kế OO; bạn sẽ đọc những cuốn sách khác về các mẫu thiết kế của FP.

ngôn ngữ bất khả tri

Không hoàn toàn. Chỉ bất khả tri về ngôn ngữ đối với các ngôn ngữ OO. Các mẫu thiết kế không áp dụng cho các ngôn ngữ thủ tục. Chúng hầu như không có ý nghĩa trong bối cảnh thiết kế cơ sở dữ liệu quan hệ. Họ không áp dụng khi thiết kế bảng tính.

một mẫu thiết kế OOP điển hình và chức năng tương đương của nó?

Ở trên không nên tồn tại. Điều đó giống như yêu cầu một đoạn mã thủ tục được viết lại thành mã OO. Ummm ... Nếu tôi dịch Fortran (hoặc C) ban đầu sang Java, tôi đã không làm gì hơn là dịch nó. Nếu tôi hoàn toàn viết lại nó thành một mô hình OO, nó sẽ không còn trông giống như Fortran hay C ban đầu nữa - nó sẽ không thể nhận ra được.

Không có ánh xạ đơn giản từ thiết kế OO đến thiết kế chức năng. Họ là những cách rất khác nhau để xem xét vấn đề.

Lập trình chức năng (như tất cả phong cách lập trình) có các mẫu thiết kế. Cơ sở dữ liệu quan hệ có các mẫu thiết kế, OO có các mẫu thiết kế và lập trình thủ tục có các mẫu thiết kế. Mọi thứ đều có mẫu thiết kế, thậm chí là kiến ​​trúc của các tòa nhà.

Các mẫu thiết kế - như một khái niệm - là một cách xây dựng vượt thời gian, không phân biệt công nghệ hay miền vấn đề. Tuy nhiên, các mẫu thiết kế cụ thể áp dụng cho các lĩnh vực và công nghệ vấn đề cụ thể.

Mọi người nghĩ về những gì họ đang làm sẽ phát hiện ra các mẫu thiết kế.


12
MVC không phải là thiết kế OO. Đó là thiết kế kiến ​​trúc - mô hình đó được áp dụng khá rộng rãi.
S.Lott

1
@ Préc: lập trình chức năng không nhất thiết phải đơn giản hơn. Trong ví dụ của bạn, có. Đối với những thứ khác, bồi thẩm đoàn vẫn ra ngoài. Nhưng bạn đã loại bỏ mẫu thiết kế Java OO và chấp nhận mẫu thiết kế FP.
S.Lott

1
+1: Tôi thích câu trả lời này hơn câu trả lời của Jalf ở trên. Mặc dù một số mẫu thiết kế giải quyết các thiếu sót trong ngôn ngữ, nhưng không phải tất cả đều làm được. Ví dụ, tôi hầu như không nói rằng mẫu thiết kế "tháo gỡ nút thắt đệ quy" giải quyết sự thiếu hụt trong ngôn ngữ, nó chỉ là một thành ngữ hữu ích để nới lỏng sự phụ thuộc.
Jon Harrop

9
Java 8 sẽ bao gồm các bao đóng hay các hàm ẩn danh aka các biểu thức lambda. Điều này sẽ làm cho mẫu thiết kế lệnh trở nên lỗi thời đối với Java. Đây là một ví dụ về sự thiếu sót ngôn ngữ, không? Họ đã thêm một tính năng còn thiếu và bây giờ bạn không cần mẫu thiết kế.
Todd Chaffee

2
+1 cho câu kết thúc. Các mẫu thiết kế có nghĩa là để đơn giản hóa việc lập trình và làm cho các chương trình kết quả hiệu quả hơn, theo những gì chúng dự định làm.
Sắp xếp

46

Nhận xét của Brian về mối liên kết chặt chẽ giữa ngôn ngữ và mô hình là điểm chính,

Phần còn thiếu của cuộc thảo luận này là khái niệm thành ngữ. Cuốn sách "Advanced C ++" của James O. Coplien là một ảnh hưởng rất lớn ở đây. Rất lâu trước khi anh ta phát hiện ra Christopher Alexander và Cột không có tên (và bạn cũng không thể nói một cách hợp lý về các mẫu mà không đọc Alexander), anh ta đã nói về tầm quan trọng của việc thành thạo các thành ngữ trong việc học ngôn ngữ. Ông đã sử dụng bản sao chuỗi trong C làm ví dụ, while(*from++ = *to++);Bạn có thể xem đây là một dải băng cho một tính năng ngôn ngữ bị thiếu (hoặc tính năng thư viện), nhưng điều thực sự quan trọng là nó là một đơn vị suy nghĩ hoặc biểu thức lớn hơn bất kỳ các bộ phận của nó.

Đó là những gì các mẫu và ngôn ngữ đang cố gắng thực hiện để cho phép chúng tôi thể hiện ý định của mình ngắn gọn hơn. Các đơn vị tư duy càng phong phú thì những suy nghĩ bạn có thể diễn đạt càng phức tạp. Có vốn từ vựng phong phú, được chia sẻ ở nhiều phạm vi - từ kiến ​​trúc hệ thống cho đến việc xoay vòng một chút - cho phép chúng ta có những cuộc trò chuyện thông minh hơn và suy nghĩ về những gì chúng ta nên làm.

Chúng ta cũng có thể, như cá nhân, học hỏi. Đó là toàn bộ điểm của bài tập. Mỗi chúng ta đều có thể hiểu và sử dụng những thứ mà chúng ta sẽ không bao giờ có thể nghĩ về bản thân. Ngôn ngữ, khung, thư viện, mô hình, thành ngữ, v.v ... đều có vị trí của chúng trong việc chia sẻ sự giàu có về trí tuệ.


8
Cảm ơn bạn! đây là những gì mô hình về "chunking khái niệm" để giảm gánh nặng nhận thức.
Randall Schulz

Và Monads chức năng chắc chắn thuộc về cuộc thảo luận này.
Greg

@RandallSchulz: các tính năng ngôn ngữ (và cách sử dụng thành ngữ của chúng, tất nhiên) cũng sẽ phù hợp với thể loại "chunking khái niệm để giảm gánh nặng nhận thức."
Roy Tinker

39

Cuốn sách GoF liên kết rõ ràng với OOP - tiêu đề là Mẫu thiết kế - Các yếu tố của phần mềm hướng đối tượng có thể tái sử dụng (nhấn mạnh của tôi).



26

Đây là một liên kết khác, thảo luận về chủ đề này: http://blog.ezyang.com/2010/05/design-potypes-in-haskel/

Trong bài đăng trên blog của mình, Edward mô tả tất cả 23 mẫu GoF gốc theo thuật ngữ Haskell.


4
Bài viết dường như không thực sự hiển thị các mẫu thiết kế trong Haskell, nhưng chỉ ra cách Haskell giải quyết các nhu cầu đó mà không cần các mẫu đã nói.
Fresheyeball

3
@Fresheyball: Phụ thuộc vào định nghĩa của bạn về các mẫu. Việc ánh xạ một chức năng qua danh sách có phải là một biến thể của mẫu Khách truy cập không? Tôi thường nghĩ rằng câu trả lời là "có." Các mẫu được cho là vượt ra ngoài một cú pháp cụ thể. Hàm đang được áp dụng có thể được bọc như một đối tượng hoặc được truyền dưới dạng con trỏ hàm, nhưng đối với tôi, khái niệm này giống nhau. Bạn có không đồng ý không?
srm

20

Khi bạn cố gắng xem xét điều này ở cấp độ "mẫu thiết kế" (nói chung) và "FP so với OOP", câu trả lời bạn sẽ tìm thấy sẽ tốt nhất.

Tuy nhiên, đi sâu hơn trên cả hai trục và xem xét các mẫu thiết kế cụ thểcác tính năng ngôn ngữ cụ thể và mọi thứ trở nên rõ ràng hơn.

Vì vậy, ví dụ, một số mẫu cụ thể, như Người truy cập , Chiến lược , LệnhNgười quan sát chắc chắn thay đổi hoặc biến mất khi sử dụng ngôn ngữ với kiểu dữ liệu đại số và khớp mẫu , đóng , hàm hạng nhất , v.v. Một số mẫu khác từ sách GoF vẫn còn 'dính xung quanh', mặc dù.

Nói chung, tôi sẽ nói rằng, theo thời gian, các mẫu cụ thể đang bị loại bỏ bởi các tính năng ngôn ngữ mới (hoặc chỉ phổ biến). Đây là quá trình tự nhiên của thiết kế ngôn ngữ; khi các ngôn ngữ trở nên cao cấp hơn, các khái niệm trừu tượng mà trước đây chỉ có thể được gọi ra trong một cuốn sách sử dụng các ví dụ giờ trở thành các ứng dụng của một tính năng ngôn ngữ hoặc thư viện cụ thể.

(Ngoài ra: đây là một blog gần đây tôi đã viết, có các liên kết khác để thảo luận nhiều hơn về các mẫu thiết kế và FP.)


Làm thế nào bạn có thể nói mô hình khách truy cập "biến mất"? Không phải nó chỉ chuyển từ "tạo giao diện Khách truy cập với các phương thức Truy cập bó" thành "sử dụng loại kết hợp và khớp mẫu" sao?
Gabe

22
Có, nhưng điều đó đã thay đổi từ một mẫu mà đó là một ý tưởng thiết kế mà bạn đọc trong một cuốn sách và áp dụng cho mã của bạn, thành "chỉ mã". Đó là, "sử dụng các loại kết hợp và khớp mẫu" chỉ là cách bạn thường viết mã bằng ngôn ngữ như vậy. (Tương tự: nếu không có ngôn ngữ nào có forcác vòng lặp và tất cả chúng chỉ có whilecác vòng lặp, thì "For" có thể là một mẫu lặp. Nhưng khi đó forchỉ là một cấu trúc được hỗ trợ bởi ngôn ngữ và cách mọi người viết mã bình thường, thì đó không phải là một mẫu - bạn không ' Không cần một mô hình, đó chỉ là mã, anh bạn.)
Brian

4
Nói một cách khác, một bài kiểm tra quỳ có lẽ không tồi đối với "đó là một mẫu" là: mã hiện tại được viết theo cách này cho một sinh viên đại học năm thứ hai chuyên ngành CS với một năm kinh nghiệm lập trình bằng ngôn ngữ của bạn. Nếu bạn chỉ cho họ mã và họ nói "đó là một thiết kế thông minh", thì đó là một mẫu. Nếu bạn cho họ xem mã, và họ đi "tốt, duh!", Thì đó không phải là một mẫu. (Và nếu bạn hiển thị "Khách truy cập" này cho bất kỳ ai đã thực hiện ML / F # / Haskell trong một năm, họ sẽ đi "tốt, duh!")
Brian

1
Brian: Tôi nghĩ rằng chúng ta chỉ có các định nghĩa khác nhau về một "mẫu". Tôi coi bất kỳ sự trừu tượng thiết kế có thể nhận dạng nào là một mẫu , trong khi bạn chỉ coi trừu tượng không rõ ràng là một mẫu . Chỉ vì C # có foreachvà Haskell mapMkhông có nghĩa là họ không có mẫu Iterator. Tôi thấy không có vấn đề gì khi nói rằng mẫu Iterator được triển khai như giao diện chung IEnumerable<T>trong C # và kiểu chữ Traversabletrong Haskell.
Gabe

Có thể các mẫu không rõ ràng được sử dụng cho các kỹ sư phần mềm nhưng tất cả các mẫu đều được sử dụng cho các nhà thiết kế ngôn ngữ. Tức là "Nếu bạn đang tạo một ngôn ngữ mới, hãy đảm bảo bao gồm một cách rõ ràng để thể hiện mẫu lặp." Ngay cả các mô hình rõ ràng cũng được quan tâm khi chúng ta bắt đầu đặt câu hỏi, "Có cú pháp nào tốt hơn để diễn đạt ý tưởng này không?" Rốt cuộc, đó là những gì dẫn dắt ai đó tạo ra foreach.
srm

16

Bài thuyết trình của Norvig ám chỉ đến một phân tích mà họ đã thực hiện trong tất cả các mẫu GoF và họ nói rằng 16 trong số 23 mẫu có triển khai đơn giản hơn trong các ngôn ngữ chức năng hoặc chỉ đơn giản là một phần của ngôn ngữ. Vì vậy, có lẽ ít nhất bảy trong số chúng là một) phức tạp như nhau hoặc b) không có trong ngôn ngữ. Thật không may cho chúng tôi, họ không được liệt kê!

Tôi nghĩ rõ ràng rằng hầu hết các mẫu "sáng tạo" hoặc "cấu trúc" trong GoF chỉ là các thủ thuật để có được các hệ thống kiểu nguyên thủy trong Java hoặc C ++ để làm những gì bạn muốn. Nhưng phần còn lại là đáng để xem xét cho dù bạn lập trình bằng ngôn ngữ nào.

Một người có thể là Nguyên mẫu; trong khi đó là một khái niệm cơ bản về JavaScript, nó phải được triển khai từ đầu bằng các ngôn ngữ khác.

Một trong những mẫu yêu thích của tôi là mẫu Null Object: đại diện cho sự vắng mặt của một thứ gì đó như là một đối tượng không có gì phù hợp. Điều này có thể dễ dàng hơn để mô hình hóa trong một ngôn ngữ chức năng. Tuy nhiên, thành tựu thực sự là sự thay đổi trong quan điểm.


2
Thật là một phân tích kỳ quặc để làm vì các mẫu GoF được thiết kế riêng cho các ngôn ngữ OOP dựa trên lớp. Có vẻ hơi giống như phân tích xem cờ lê đường ống có tốt để làm công việc điện hay không.
khoan hồng

@munificent: Không hẳn. Hướng đối tượng cung cấp đa hình; lập trình chức năng thường cung cấp đa hình.
Marcin

@Marcin một lập trình viên OO có nghĩa là một cái gì đó rất khác biệt bởi đa hình so với một lập trình viên chức năng.
AndrewC

@AndrewC Tôi không đồng ý. Lập trình viên OO có thể nghĩ rằng họ có ý nghĩa khác, nhưng họ thì không.
Marcin

3
@Marcin Theo kinh nghiệm của tôi, một lập trình viên OO thường đề cập đến đa hình phụ (thường chỉ sử dụng Object), sử dụng các phôi để đạt được nó, hoặc đa hình ad-hoc (quá tải, v.v.). Khi một lập trình viên chức năng nói đa hình, họ có nghĩa là đa hình tham số (nghĩa là hoạt động với mọi loại dữ liệu - Int, function, list), có lẽ giống như lập trình chung của OO hơn là giống như mọi thứ mà các lập trình viên OO thường gọi là đa hình.
AndrewC

15

Tôi sẽ nói rằng khi bạn có một ngôn ngữ như Lisp với sự hỗ trợ cho các macro, thì bạn có thể xây dựng các bản tóm tắt dành riêng cho tên miền, các bản tóm tắt thường tốt hơn nhiều so với các giải pháp thành ngữ chung.


Tôi hoàn toàn lạc lối. Để lên một cái gì đó với sự trừu tượng ... Điều đó có nghĩa là gì?
tuinstoel

2
Bạn có thể xây dựng các bản tóm tắt cụ thể của miền (thậm chí cả phần nhúng) mà không cần macro. Macro chỉ cho phép bạn làm đẹp chúng bằng cách thêm cú pháp tùy chỉnh.
Jon Harrop

2
Bạn có thể nghĩ Lisp là một bộ Legos để xây dựng ngôn ngữ lập trình - đó là ngôn ngữ nhưng cũng là ngôn ngữ kim loại. Điều đó có nghĩa là đối với bất kỳ miền có vấn đề nào, bạn có thể tùy chỉnh thiết kế một ngôn ngữ không có bất kỳ thiếu sót rõ ràng nào. Nó sẽ yêu cầu một số thực hành và Kurt Gödel có thể không đồng ý, nhưng đáng để dành chút thời gian với Lisp để xem những gì nó mang đến cho bảng (gợi ý, macro).
Greg

9

Và thậm chí các giải pháp mẫu thiết kế OO là ngôn ngữ cụ thể.

Các mẫu thiết kế là giải pháp cho các vấn đề phổ biến mà ngôn ngữ lập trình của bạn không giải quyết được cho bạn. Trong Java, mẫu Singleton giải quyết vấn đề có một không hai (đơn giản hóa).

Trong Scala, bạn có một cấu trúc cấp cao nhất được gọi là Object ngoài Class. Nó ngay lập tức lười biếng và chỉ có một. Bạn không cần phải sử dụng mẫu Singleton để lấy Singleton. Đó là một phần của ngôn ngữ.


8

Các mẫu là cách giải quyết các vấn đề tương tự được nhìn thấy nhiều lần, và sau đó được mô tả và ghi lại. Vì vậy, không, FP sẽ không thay thế các mẫu; tuy nhiên, FP có thể tạo các mẫu mới và làm cho một số mẫu "thực tiễn tốt nhất" hiện tại "lỗi thời".


4
Các mẫu GoP là cách giải quyết vấn đề về những hạn chế của một loại ngôn ngữ lập trình cụ thể cản trở bạn. Ví dụ: "Tôi muốn gián tiếp trên các lớp và bảo họ tạo các đối tượng" -> "Bạn không thể, nhưng bạn có thể tạo các đối tượng giống như siêu dữ liệu được gọi là Factory". "Tôi muốn gửi nhiều lần" -> "Bạn không thể, nhưng có mê cung bạn có thể thực hiện được gọi là Mẫu khách truy cập". V.v. Không có mẫu nào có ý nghĩa nếu bạn không sử dụng ngôn ngữ OOP với các giới hạn cụ thể.
Kaz

1
Tôi không biết về "không" trong số chúng có ý nghĩa trong các ngôn ngữ khác, nhưng tôi đồng ý rằng rất nhiều trong số chúng không có ý nghĩa trong các ngôn ngữ khác. Adaptor và Bridge dường như có nhiều khả năng đa ngôn ngữ hơn, giảm một chút cho khách truy cập và có lẽ ít hơn một chút cho người nghe. Tuy nhiên, các mẫu trên các ngôn ngữ luôn phải chịu kiểu "cách thực hiện thao tác của ngôn ngữ X trong ngôn ngữ Y" để che giấu ranh giới tự nhiên của ngôn ngữ. Một ví dụ hoàn hảo là mẫu Singleton, về cơ bản, làm thế nào để tôi có được C toàn cầu trong OOP? (mà tôi sẽ trả lời, bạn không nên).
Edwin Buck

1
Tôi thứ hai Kaz: Mô hình không phải là "cách giải quyết các vấn đề tương tự được gặp lại nhiều lần" mà là "cách giải quyết các vấn đề tương tự được gặp lại nhiều lần VÀ phải viết lại nhiều lần vì ngôn ngữ không cho phép một người chỉ viết một lần ". Nói cách khác, nếu ngôn ngữ cho phép trích xuất / trừu tượng hóa mẫu trong thư viện / lớp / mô-đun, v.v ... nó sẽ dừng là một mẫu mà trở thành thư viện / lớp / mô-đun. Trong FP, việc trích xuất / trừu tượng bit mã thành hàm dễ dàng hơn nhiều, do đó "mẫu" được chuyển đổi dễ dàng hơn trong mã có thể sử dụng lại làm cho chúng không phải là mẫu.
mb14

1
Giải thích của bạn được hoan nghênh, nhưng cuốn sách GoF đã rõ ràng để xác định một mẫu và nếu bạn đọc các chương giới thiệu, nó không nói gì về ngôn ngữ hoặc điểm yếu của ngôn ngữ. Chắc chắn một số ngôn ngữ có các khu vực sẽ khiến chúng sử dụng một số mẫu thường xuyên hơn, nhưng cho dù bạn viết nó mười lần (cắt và dán) hoặc thực hiện nó một lần với mười lần thực hiện (phân loại phụ) hoặc có một khung được cấu hình để thực hiện mười lần một chút những cách khác nhau, chỉ là một chi tiết thực hiện của mô hình được phơi bày.
Edwin Buck

1
Lang thang trở lại cuộc trò chuyện này sau nhiều năm, tôi nghĩ rằng rất nhiều người liên kết các Mẫu với một ngôn ngữ lập trình cụ thể hoặc một mô hình lập trình cụ thể. Chúng có thể được sử dụng trong bối cảnh như vậy, nhưng chúng đã tồn tại trước khi lập trình. "Một cách xây dựng vượt thời gian" thảo luận về việc xây dựng kiến ​​trúc và quy hoạch cộng đồng. Điều này ngụ ý rằng các kỹ thuật hướng mẫu có thể được sử dụng bên ngoài "giới hạn của ngôn ngữ" trừ khi bạn muốn gọi tòa nhà xây dựng là ngôn ngữ lập trình :)
Edwin Buck

8

Như những người khác đã nói, có những mẫu cụ thể cho lập trình chức năng. Tôi nghĩ rằng vấn đề loại bỏ các mẫu thiết kế không phải là vấn đề chuyển sang chức năng, mà là vấn đề về tính năng ngôn ngữ .

Hãy xem Scala làm thế nào với "mẫu đơn": bạn chỉ cần khai báo một đối tượng thay vì một lớp. Một tính năng khác, khớp mẫu, giúp tránh sự vụng về của mẫu khách truy cập. Xem so sánh ở đây: Kết hợp mẫu của Scala = Mẫu khách truy cập trên steroid

Và Scala, giống như F #, là sự hợp nhất của chức năng OO. Tôi không biết về F #, nhưng nó có thể có các loại tính năng này.

Đóng cửa có mặt trong ngôn ngữ chức năng, nhưng chúng không cần phải bị hạn chế đối với chúng. Họ giúp với mô hình đại biểu.

Thêm một quan sát. Đoạn mã này thực hiện một mẫu: nó rất cổ điển và nó rất nguyên tố đến nỗi chúng ta thường không nghĩ nó là một "mẫu", nhưng chắc chắn là:

for(int i = 0; i < myList.size(); i++) { doWhatever(myList.get(i)); }

Các ngôn ngữ bắt buộc như Java và C # đã áp dụng cơ bản là một cấu trúc chức năng để đối phó với điều này: "foreach".


Tôi muốn nói rằng Scala bao gồm hỗ trợ hạng nhất cho mẫu singleton. Mẫu vẫn còn đó, nhưng mã soạn sẵn cần thiết để áp dụng mẫu được giảm đáng kể so với Java.
JacquesB

Nếu ý kiến ​​giống như một ******, thì ... Hãy nhìn vào phần còn lại của câu trả lời. "bạn chỉ đơn giản khai báo một đối tượng thay vì một lớp" là rất đúng, tôi rõ ràng sẽ gọi nó là một đối tượng theo nghĩa đen (ví dụ var singleton = {};). Tôi cũng thích đề cập về mô hình foreach. Thật không may, có vẻ như hầu hết những người trả lời / nhận xét về câu hỏi này không hiểu lập trình chức năng và muốn biện minh cho việc sử dụng các mẫu thiết kế OOP. +1 để cung cấp các ví dụ cụ thể, tôi sẽ cung cấp thêm nếu tôi có thể.
Evan Plaice

.... các thành viên lớp và cho phép nhiều kế thừa (loại bỏ sự cần thiết của các hợp đồng giao diện).
Evan Plaice

8

Các mẫu thiết kế GoF đang mã hóa các công thức giải pháp thay thế cho các ngôn ngữ OO là hậu duệ của Simula 67 , như Java và C ++.

Hầu hết các "bệnh" được điều trị bởi các mẫu thiết kế là do:

  • các lớp gõ tĩnh, xác định các đối tượng, nhưng không phải là các đối tượng;
  • hạn chế gửi một lần duy nhất (chỉ sử dụng đối số ngoài cùng bên trái để chọn phương thức, các đối số còn lại chỉ được coi là loại tĩnh: nếu chúng có kiểu động, tùy thuộc vào phương pháp sắp xếp theo phương pháp ad-hoc);
  • phân biệt giữa các lệnh gọi hàm thông thường và các hàm gọi hướng đối tượng, nghĩa là các hàm hướng đối tượng không thể được chuyển qua dưới dạng đối số chức năng trong đó các hàm thông thường được mong đợi và ngược lại; và
  • phân biệt giữa "loại cơ sở" và "loại lớp".

Không có một mẫu nào trong số các mẫu thiết kế này không biến mất trong Hệ thống đối tượng Lisp chung, mặc dù giải pháp được cấu trúc về cơ bản giống như trong mẫu thiết kế tương ứng. (Hơn nữa, hệ thống đối tượng đó có trước cuốn sách GoF hơn một thập kỷ. Lisp thông thường đã trở thành một tiêu chuẩn ANSI cùng năm với cuốn sách đó được xuất bản lần đầu tiên.)

Đối với lập trình chức năng có liên quan, việc các mẫu áp dụng cho nó có phụ thuộc vào việc ngôn ngữ lập trình chức năng đã cho có một loại hệ thống đối tượng hay không và liệu nó có được mô hình hóa theo các hệ thống đối tượng được hưởng lợi từ các mẫu đó hay không. Loại hướng đối tượng đó không kết hợp tốt với lập trình chức năng, bởi vì sự đột biến của trạng thái nằm ở phía trước và trung tâm.

Truy cập xây dựng và không đột biến tương thích với lập trình chức năng và do đó, các mẫu có liên quan đến truy cập trừu tượng hoặc xây dựng có thể được áp dụng: các mẫu như Factory, Facade, Proxy, Decorator và visitor.

Mặt khác, các mô hình hành vi như Nhà nước và Chiến lược có thể không được áp dụng trực tiếp trong OOP chức năng vì sự đột biến của nhà nước là cốt lõi của chúng. Điều này không có nghĩa là họ không áp dụng; có lẽ họ bằng cách nào đó áp dụng kết hợp với bất kỳ thủ thuật nào có sẵn để mô phỏng trạng thái đột biến.


2
"Các mẫu thiết kế GoF đang mã hóa các công thức giải pháp thay thế" chỉ đơn giản là một tuyên bố sai.
John Peters

7

Tôi muốn viết một vài bài báo xuất sắc nhưng hơi dày đặc của Jeremy Gibbons: "Thiết kế các mẫu như các chương trình chung kiểu dữ liệu bậc cao" và "Bản chất của mẫu Iterator" (cả hai đều có ở đây: http: // www. comlab.ox.ac.uk/jeremy.g Ribbon / public / ).

Cả hai đều mô tả cách các cấu trúc chức năng thành ngữ bao phủ địa hình được bao phủ bởi các mẫu thiết kế cụ thể trong các cài đặt (hướng đối tượng) khác.


6

Bạn không thể có cuộc thảo luận này mà không đưa ra các hệ thống loại.

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ố đó.

Đó là bởi vì các tính năng này không giải quyết các vấn đề tương tự như OOP ... chúng là các lựa chọn thay thế cho lập trình bắt buộc. Câu trả lời của FP cho OOP nằm trong các hệ thống kiểu ML và Haskell ... cụ thể là các kiểu tổng, kiểu dữ liệu trừu tượng, mô-đun ML và kiểu chữ Haskell.

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)

Điều đầu tiên mà typeclass làm là loại bỏ sự cần thiết của singletons.

Bạn có thể xem qua danh sách 23 và loại bỏ nhiều hơn, nhưng tôi không có thời gian để làm ngay bây giờ.


6
Làm thế nào để các kiểu chữ (tương đương FP của giao diện OOP) loại bỏ sự cần thiết của singletons (tương đương với FP của trạng thái toàn cầu)?
Gabe

4

Tôi nghĩ rằng chỉ có hai Mẫu thiết kế GoF được thiết kế để đưa logic lập trình chức năng vào ngôn ngữ OO tự nhiên. Tôi nghĩ về Chiến lược và Chỉ huy. Một số mẫu thiết kế GoF khác có thể được sửa đổi bằng lập trình chức năng để đơn giản hóa thiết kế và giữ nguyên mục đích.


4
Điều quan trọng là, điểm chính của nhiều mẫu là khai thác tính đa hình để làm những việc mà sự hỗ trợ tốt cho các khái niệm FP có thể cho phép tự động. (Ví dụ, hầu hết các hóa thân mà tôi đã thấy về Builder, chỉ là một nửa cà ri.) Một khi bạn có thể dễ dàng coi các hàm là các giá trị, các mẫu thường đơn giản hóa đến mức tầm thường. Chúng trở thành "vượt qua một cuộc gọi lại" hoặc "có một từ điển các cuộc gọi lại" - và các lớp xây dựng khác nhau, ví dụ, tất cả có thể biến mất. IMO một mẫu dừng lại là một mẫu một khi nó đủ tầm thường để làm mọi thứ hoạt động , chứ không phải là thứ bạn cần thực hiện.
cHao

4

Thực chất là !

  • Khi một mẫu bao quanh các tính năng bị thiếu (các hàm bậc cao, xử lý luồng ...) mà cực kỳ tạo điều kiện cho thành phần .
  • Sự cần thiết phải viết lại việc thực hiện các mẫu lặp đi lặp lại có thể được coi là một mùi ngôn ngữ .

Bên cạnh đó, trang này (AreDesignPotypesMissingL LanguageFeatures) cung cấp bảng dịch "mẫu / tính năng" và một số thảo luận hay, nếu bạn sẵn sàng đào.


3

Lập trình chức năng không thay thế các mẫu thiết kế. Các mẫu thiết kế không thể thay thế.

Các mẫu đơn giản tồn tại; chúng nổi lên theo thời gian. Cuốn sách GoF chính thức hóa một số trong số họ. Nếu các mô hình mới được đưa ra ánh sáng khi các nhà phát triển sử dụng các ngôn ngữ lập trình chức năng là công cụ thú vị, và có lẽ cũng sẽ có những cuốn sách viết về chúng.


1
Mẫu thiết kế không thể thay thế? Đó là một chút khép kín tôi nghĩ. Tất cả chúng ta có thể đồng ý rằng các mẫu thiết kế là để giải quyết các vấn đề lập trình, và ít nhất tôi muốn hy vọng rằng một ngày nào đó chúng ta có thể giải quyết những vấn đề đó mà không cần các mẫu thiết kế.
Đô thị

3
Bất kỳ mẫu cụ thể nào cũng có thể thay thế được, nhưng khái niệm về các mẫu thì không thể. Hãy nhớ rằng thuật ngữ "mẫu" phát sinh trong lĩnh vực kiến trúc .
Frank Shearar

1
Các mẫu không có nghĩa là để giải quyết các vấn đề lập trình. Các mẫu là cách chúng tôi lập trình. Các tài liệu về các mẫu có ý nghĩa để giúp giải quyết các vấn đề lập trình.
Torbjørn

3
@ Torbjørn: Các mẫu là cách chúng ta lập trình khi ngôn ngữ cản trở . Chúng tồn tại do một số điểm không phù hợp giữa hành vi mong muốn của chương trình và khả năng tích hợp của ngôn ngữ, trong đó các yêu cầu và khả năng không ánh xạ tốt hoặc ánh xạ mơ hồ. Nếu không có điều đó, sẽ không có mô hình; bạn có một triển khai chỉ là cách mọi thứ được thực hiện và các triển khai khác thực sự không đáng để xem xét.
cHao

1
Ngoại trừ các mẫu thực sự tồn tại chỉ để tạo điều kiện giao tiếp. Không có mục đích nào khác. Và trong tất cả các cuộc họp thiết kế mà tôi đã tham dự trong nhiều năm qua, một cuộc thảo luận về thuật toán là điều quan trọng, không phải là mô hình. Các mô hình hiếm khi giải thích những gì đang thực sự xảy ra trong bất kỳ ý nghĩa có ý nghĩa. Nó có giải thích chính xác các tác động O (n) so với O (n Log (n)) không? Không. Nó có giải thích cách dễ dàng phù hợp với kiến ​​trúc hiện tại không? Không. Thảo luận về thuật toán quy mô đầy đủ. Tôi không tranh luận rằng các mẫu nên được loại bỏ mỗi se, nhưng nếu có, hầu như không có gì phải chịu hậu quả.

3

Trong cuốn sách mới năm 2013 có tên "Các mẫu lập trình chức năng- trong Scala và Clojure" của tác giả Michael.B. Linn thực hiện một công việc tốt so sánh và cung cấp thay thế trong nhiều trường hợp cho các mẫu GoF và cũng thảo luận về các mẫu chức năng mới hơn như 'đệ quy đuôi', 'ghi nhớ', 'chuỗi lười biếng', v.v.

Cuốn sách này có sẵn trên Amazon. Tôi thấy nó rất nhiều thông tin và đáng khích lệ khi đến từ nền tảng OO của một vài thập kỷ.


3

Các mẫu OOP và GoF xử lý các trạng thái. OOP mô hình thực tế để giữ cho cơ sở mã càng gần càng tốt với các yêu cầu đã cho của thực tế. Các mẫu thiết kế của GoF là các mẫu được xác định để giải quyết các vấn đề trong thế giới thực nguyên tử. Họ xử lý vấn đề của nhà nước một cách ngữ nghĩa.

Vì trong lập trình chức năng thực không tồn tại trạng thái, việc áp dụng các mẫu GoF không có ý nghĩa gì. Không có các mẫu thiết kế chức năng theo cùng một cách có các mẫu thiết kế GoF. Mỗi mẫu thiết kế chức năng là nhân tạo trái ngược với thực tế vì các chức năng là cấu trúc của toán học và không phải là thực tế.

Các hàm thiếu khái niệm về thời gian vì chúng luôn trả về cùng một giá trị bất kể thời gian hiện tại là gì trừ khi thời gian là một phần của các tham số hàm khiến cho việc thực hiện "yêu cầu trong tương lai" thực sự khó khăn. Các ngôn ngữ lai trộn các khái niệm đó làm cho các ngôn ngữ không phải là ngôn ngữ lập trình chức năng thực sự.

Các ngôn ngữ chức năng đang tăng chỉ vì một điều: các hạn chế tự nhiên hiện tại của vật lý. Bộ xử lý ngày nay bị giới hạn về tốc độ hướng dẫn xử lý do các quy luật vật lý. Bạn thấy sự trì trệ trong tần số xung nhịp nhưng sự mở rộng trong xử lý lõi. Đó là lý do tại sao các hướng dẫn song song ngày càng trở nên quan trọng hơn để tăng tốc độ của các ứng dụng hiện đại. Vì định nghĩa chức năng theo định nghĩa không có trạng thái và do đó không có tác dụng phụ nên việc xử lý các chức năng một cách an toàn song song là an toàn.

Các mẫu GoF không bị lỗi thời. Họ ít nhất là cần thiết để mô hình hóa các yêu cầu thế giới thực. Nhưng nếu bạn sử dụng một ngôn ngữ lập trình chức năng, bạn phải chuyển đổi chúng thành tương đương lai của chúng. Cuối cùng, bạn không có cơ hội để thực hiện các chương trình chức năng nếu bạn sử dụng kiên trì. Đối với các yếu tố lai của chương trình của bạn, vẫn cần phải sử dụng các mẫu GoF. Đối với bất kỳ yếu tố nào khác hoàn toàn là chức năng, không cần thiết phải sử dụng các mẫu GoF vì không có trạng thái.

Vì các mẫu GoF không cần thiết cho lập trình chức năng thực tế, điều đó không có nghĩa là các nguyên tắc RẮN không nên được áp dụng. Các nguyên tắc RẮN vượt ra ngoài mọi mô hình ngôn ngữ.


2
FP có thể có trạng thái - chỉ không có trạng thái toàn cầu, chia sẻ hoặc có thể thay đổi.
vt5491

2

Trong lập trình chức năng, các mẫu thiết kế có một ý nghĩa khác. Trong thực tế, hầu hết các mẫu thiết kế OOP là không cần thiết trong lập trình chức năng do mức độ trừu tượng hóa cao hơn và HOF được sử dụng làm khối xây dựng.

Nguyên tắc của HOF có nghĩa là các hàm có thể được truyền dưới dạng đối số cho các hàm khác. và các hàm có thể trả về giá trị.


1

Như câu trả lời được chấp nhận đã nói, OOP và FP đều có mẫu cụ thể của họ.

Tuy nhiên, có một số mẫu phổ biến đến mức tất cả các nền tảng lập trình mà tôi có thể nghĩ nên có. Dưới đây là danh sách (không đầy đủ):

  • Bộ chuyển đổi. Tôi khó có thể nghĩ về một nền tảng lập trình hữu ích, toàn diện (và tự hoàn thành) đến mức không cần phải nói chuyện với thế giới. Nếu nó sẽ làm như vậy, một bộ chuyển đổi chắc chắn là cần thiết.

  • Mặt tiền. Bất kỳ nền tảng lập trình nào có thể xử lý mã nguồn lớn đều có thể mô đun hóa. Nếu bạn đã tạo một mô-đun cho các phần khác của chương trình, bạn sẽ muốn ẩn các phần "bẩn" của mã và cung cấp cho nó một giao diện đẹp.

  • Thông dịch viên. Nói chung, bất kỳ chương trình nào cũng chỉ thực hiện hai điều: phân tích cú pháp đầu vào và đầu ra in. Đầu vào chuột cần được phân tích cú pháp và các tiện ích cửa sổ cần được in ra. Do đó, việc có một trình thông dịch nhúng giúp chương trình có thêm sức mạnh để tùy chỉnh mọi thứ.

Ngoài ra, tôi nhận thấy trong một ngôn ngữ FP điển hình, Haskell, có một cái gì đó tương tự như các mẫu GoF, nhưng với các tên khác nhau. Theo tôi điều này cho thấy họ đã ở đó vì có một số vấn đề phổ biến cần giải quyết bằng cả hai ngôn ngữ FP và OOP.

  • Monad biến áp và trang trí. Cái trước được sử dụng để thêm khả năng bổ sung vào một đơn nguyên hiện có, cái sau thêm khả năng bổ sung cho một đối tượng hiện có.

1

Tôi nghĩ rằng mỗi mô hình phục vụ một mục đích khác nhau và như vậy không thể so sánh theo cách này.

Tôi chưa nghe nói rằng các mẫu thiết kế GoF có thể áp dụng cho mọi ngôn ngữ. Tôi đã nghe nói rằng chúng có thể áp dụng cho tất cả các ngôn ngữ OOP . Nếu bạn sử dụng lập trình chức năng thì miền của các vấn đề mà bạn giải quyết khác với các ngôn ngữ OO.

Tôi sẽ không sử dụng ngôn ngữ chức năng để viết giao diện người dùng, nhưng một trong những ngôn ngữ OO như C # hoặc Java sẽ giúp công việc này dễ dàng hơn. Nếu tôi đang viết một ngôn ngữ chức năng thì tôi sẽ không xem xét sử dụng các mẫu thiết kế OO.


1

OOP và FP có các mục tiêu khác nhau. OOP nhằm mục đích gói gọn sự phức tạp / bộ phận chuyển động của các thành phần phần mềm và FP nhằm mục đích giảm thiểu sự phức tạp và phụ thuộc của các thành phần phần mềm.

Tuy nhiên, hai mô hình này không nhất thiết là 100% mâu thuẫn và có thể được áp dụng cùng nhau để có được lợi ích từ cả hai thế giới.

Ngay cả với một ngôn ngữ không hỗ trợ lập trình chức năng như C #, bạn có thể viết mã chức năng nếu bạn hiểu các nguyên tắc FP. Tương tự như vậy, bạn có thể áp dụng các nguyên tắc OOP bằng F # nếu bạn hiểu các nguyên tắc, mẫu và các thực tiễn tốt nhất của OOP. Bạn sẽ có lựa chọn đúng dựa trên tình huống và vấn đề mà bạn cố gắng giải quyết, bất kể ngôn ngữ lập trình bạn sử dụng là gì.


1

Một số mẫu dễ thực hiện hơn trong một ngôn ngữ hỗ trợ FP. Ví dụ: Chiến lược có thể được thực hiện bằng cách sử dụng độc đáo bằng cách đóng. Tuy nhiên, tùy thuộc vào ngữ cảnh, bạn có thể thích triển khai Chiến lược bằng cách sử dụng cách tiếp cận dựa trên lớp, cho biết bản thân các chiến lược khá phức tạp và / hoặc chia sẻ cấu trúc mà bạn muốn lập mô hình bằng Phương thức mẫu.

Theo kinh nghiệm của tôi, phát triển theo ngôn ngữ đa mô hình (Ruby), việc triển khai FP hoạt động tốt trong các trường hợp đơn giản, nhưng trong bối cảnh phức tạp hơn, cách tiếp cận dựa trên GoF OOP là phù hợp hơn.

Cách tiếp cận FP không thay thế cách tiếp cận OOP, nó bổ sung cho nó.


0

Đặc điểm tối quan trọng của lập trình chức năng, IMHO, là bạn đang lập trình không có gì ngoài các biểu thức - các biểu thức trong các biểu thức mà tất cả đều đánh giá đến biểu thức cuối cùng, cuối cùng "làm ấm máy khi được đánh giá".

Đặc điểm tối quan trọng của lập trình hướng đối tượng, IMHO là bạn đang lập trình với các đối tượng có trạng thái bên trong. Bạn không thể có trạng thái nội bộ trong các hàm thuần túy - ngôn ngữ lập trình hướng đối tượng cần các câu lệnh để làm cho mọi thứ xảy ra. (Không có tuyên bố nào trong lập trình chức năng.)

Bạn đang so sách những quả táo và những quả cam. Các mẫu lập trình hướng đối tượng không áp dụng cho lập trình hàm, bởi vì lập trình hàm là lập trình với các biểu thức và lập trình hướng đối tượng là lập trình với trạng thái bên trong.


Hmm, tôi nên nhận thấy rằng câu hỏi đã mười một tuổi trước khi trả lời. :-)
Jim Flood

0

Tự ôm mình.

Nó sẽ làm cho nhiều người nghe tôi tuyên bố rằng đã thay thế các mẫu thiết kế và gỡ lỗi RẮN và KHÔ. Tôi không là ai cả. Tuy nhiên, tôi đã mô hình hóa chính xác kiến ​​trúc hợp tác (sản xuất) và xuất bản các quy tắc xây dựng quy trình trực tuyến cùng với mã và khoa học đằng sau nó tại trang web của tôi http://www.powersemantics.com/ .

Lập luận của tôi là các mẫu thiết kế cố gắng đạt được cái mà sản xuất gọi là "tùy biến đại chúng", một hình thức quy trình trong đó mọi bước có thể được định hình lại, tái cấu trúc và mở rộng. Bạn có thể nghĩ về các quá trình như các tập lệnh chưa biên dịch. Tôi sẽ không lặp lại lập luận (trực tuyến) của tôi ở đây. Nói tóm lại, kiến ​​trúc tùy biến đại chúng của tôi thay thế các mẫu thiết kế bằng cách đạt được sự linh hoạt đó mà không có bất kỳ ngữ nghĩa lộn xộn nào. Tôi đã ngạc nhiên khi mô hình của tôi hoạt động rất tốt, nhưng cách các lập trình viên viết mã đơn giản là không giữ được ngọn nến trong cách sản xuất tổ chức công việc hợp tác.

  • Sản xuất = mỗi bước tương tác với một sản phẩm
  • OOP = mỗi bước tương tác với chính nó và các mô-đun khác, chuyển sản phẩm từ điểm này sang điểm khác như nhân viên văn phòng vô dụng

Kiến trúc này không bao giờ cần tái cấu trúc. Ngoài ra còn có các quy tắc liên quan đến tập trung và phân phối ảnh hưởng đến sự phức tạp. Nhưng để trả lời câu hỏi của bạn, lập trình chức năng là một tập hợp ngữ nghĩa xử lý khác, không phải là kiến ​​trúc cho các quy trình tùy chỉnh hàng loạt trong đó 1) định tuyến nguồn tồn tại dưới dạng tài liệu (tập lệnh) mà wielder có thể viết lại trước khi bắn và 2) mô-đun có thể dễ dàng và tự động thêm hoặc loại bỏ.

Chúng ta có thể nói OOP là mô hình "quá trình mã hóa cứng" và các mẫu thiết kế là cách để tránh mô hình đó. Nhưng đó là những gì tùy biến đại chúng là tất cả về. Các mẫu thiết kế thể hiện các quy trình động như mã cứng lộn xộn. Không có điểm nào cả. Thực tế là F # cho phép truyền các hàm như một tham số có nghĩa là các ngôn ngữ chức năng và OOP đều cố gắng tự thực hiện tùy chỉnh hàng loạt.

Làm thế nào khó hiểu là với người đọc, mã cứng đại diện cho kịch bản? Hoàn toàn không nếu bạn nghĩ rằng người tiêu dùng máy tính của bạn trả tiền cho các tính năng như vậy, nhưng với tôi các tính năng như vậy là lãng phí ngữ nghĩa. Chúng là vô nghĩa, bởi vì mục đích của việc tùy biến đại chúng là làm cho các quy trình trở nên năng động , không chỉ năng động đối với lập trình viên đang sử dụng Visual Studio.


0

Nó, trong đó một PL chức năng cấp cao (như OCaml, với các lớp, mô-đun, v.v.) chắc chắn thay thế các ngôn ngữ mệnh lệnh OOP về tính linh hoạt và khả năng diễn đạt. Các tóm tắt không bị rò rỉ, bạn có thể thể hiện hầu hết các ý tưởng của mình trực tiếp trong chương trình. Do đó, vâng, nó thay thế các mẫu thiết kế, hầu hết trong số đó là đơn giản hóa một cách lố bịch so với các mẫu chức năng dù sao đi nữa.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.