Lập trình chức năng so với lập trình hướng đối tượng [đóng]


784

Cho đến nay, tôi chủ yếu tiếp xúc với lập trình OO và mong muốn học một ngôn ngữ chức năng. Câu hỏi của tôi là:

  • Khi nào bạn chọn lập trình chức năng hơn hướng đối tượng?
  • Các định nghĩa vấn đề điển hình trong đó lập trình chức năng là một lựa chọn tốt hơn là gì?



1
câu hỏi tương tự cs.se cũng đã đóng lại ví dụ trong đó lập trình hàm cho kết quả tốt hơn kiểu bắt buộc . Sự khôn ngoan thông thường dường như là cái này không vượt trội so với cái kia, hoặc chúng không thể so sánh với các tiêu chí đơn giản, hoặc chúng được sử dụng cho các mục đích khác nhau ... lập trình chức năng có nguồn gốc và sử dụng khoa học / khoa học hơn và ít phổ biến hơn trong công nghiệp , do đó, câu hỏi cũng đặt ra một "xung đột công nghiệp / hàn lâm" không thể giải quyết được. một tham chiếu cổ điển cho thấy OOP tinh tế trong lập trình chức năng, sách SICP / MIT
vzn

" OO làm cho mã dễ hiểu bằng cách đóng gói các bộ phận chuyển động. FP làm cho mã dễ hiểu bằng cách giảm thiểu các bộ phận chuyển động. " --Micheal Feathers, 2010
jaco0646

Câu trả lời:


1193

Khi nào bạn chọn lập trình chức năng theo hướng đối tượng?

Khi bạn dự đoán một loại tiến hóa phần mềm khác:

  • Các ngôn ngữ hướng đối tượng là tốt khi bạn có một bộ hoạt động cố định trên mọi thứ và khi mã của bạn phát triển, bạn chủ yếu thêm những thứ mới. Điều này có thể được thực hiện bằng cách thêm các lớp mới thực hiện các phương thức hiện có và các lớp hiện có được để lại một mình.

  • Các ngôn ngữ chức năng là tốt khi bạn có một tập hợp các thứ cố định và khi mã của bạn phát triển, bạn chủ yếu thêm các hoạt động mới vào những thứ hiện có. Điều này có thể được thực hiện bằng cách thêm các hàm mới tính toán với các kiểu dữ liệu hiện có và các hàm hiện có được để lại một mình.

Khi tiến hóa đi sai hướng, bạn có vấn đề:

  • Thêm một hoạt động mới vào một chương trình hướng đối tượng có thể yêu cầu chỉnh sửa nhiều định nghĩa lớp để thêm một phương thức mới.

  • Thêm một loại điều mới vào một chương trình chức năng có thể yêu cầu chỉnh sửa nhiều định nghĩa chức năng để thêm trường hợp mới.

Vấn đề này đã được biết đến trong nhiều năm; vào năm 1998, Phil Wadler đã gọi nó là "vấn đề biểu hiện" . Mặc dù một số nhà nghiên cứu nghĩ rằng vấn đề biểu hiện có thể được giải quyết với các tính năng ngôn ngữ như mixins, một giải pháp được chấp nhận rộng rãi vẫn chưa được đưa vào dòng chính.

Các định nghĩa vấn đề điển hình trong đó lập trình chức năng là một lựa chọn tốt hơn là gì?

Các ngôn ngữ chức năng vượt trội trong việc thao tác dữ liệu tượng trưng ở dạng cây. Một ví dụ yêu thích là trình biên dịch, trong đó ngôn ngữ nguồn và ngôn ngữ trung gian thay đổi hiếm khi (hầu hết là cùng một thứ ), nhưng người viết trình biên dịch luôn thêm các bản dịch mới và cải tiến mã hoặc tối ưu hóa (hoạt động mới trên mọi thứ). Biên dịch và dịch thuật nói chung là "ứng dụng sát thủ" cho các ngôn ngữ chức năng.


119
Có một số zen nghiêm trọng đằng sau câu trả lời này. Tôi nghĩ rằng nó làm sáng tỏ thực tế rằng một số mẫu thiết kế OOP (Khách truy cập) thực sự là những bản hack nhằm khắc phục vấn đề thêm các hoạt động mới.
Giải pháp dữ liệu Jacobs

54
Trong JavaScript, bạn có thể có tất cả mọi thứ.
Erik Reppen

61
@ErikReppen tại thời điểm nào câu hỏi phát sinh, khi nào bạn chọn sử dụng các tính năng chức năng và khi nào bạn chọn sử dụng các tính năng hướng đối tượng?
Norman Ramsey

7
@NormanRamsey Không có gì lạ khi kết hợp nó trong JS và các hàm hạng nhất được gắn với rất nhiều tính năng liên quan đến JS OOP. Sắp xếp mảng của JS có các chức năng như một đối số có thể tạo ra một số cấu trúc dữ liệu mạnh mẽ. Đóng + một chức năng đã qua được sử dụng để giữ cho các đối tượng jquery nói rất nhẹ về bộ nhớ vì hầu hết các phương thức chỉ là tham chiếu. V.v ...
Erik Reppen

9
@NormanRamsey: Câu trả lời rất hay, dọc theo dòng của SICP. Theo phân loại này, lập trình chức năng và thủ tục được nhóm lại với nhau ở phía đối diện của lập trình hướng đối tượng. Điều này có thể giải thích sự bùng nổ của OOP vào cuối những năm 1980 đầu những năm 1990: khi GUI trở thành dòng chính OOP đã chứng tỏ là một cách tiếp cận tốt để mô hình hóa chúng bởi vì bạn thường có một bộ thao tác cố định (vẽ, mở, đóng, thay đổi kích thước) và ngày càng nhiều vật dụng. Tất nhiên, điều này không có nghĩa là OOP tốt hơn thủ tục cho bất kỳ ứng dụng nào, như bạn đã minh họa.
Giorgio

177

Bạn không nhất thiết phải lựa chọn giữa hai mô hình. Bạn có thể viết phần mềm với kiến ​​trúc OO bằng nhiều khái niệm chức năng. FP và OOP là trực giao trong tự nhiên .

Lấy ví dụ C #. Bạn có thể nói nó chủ yếu là OOP, nhưng có nhiều khái niệm và cấu trúc FP. Nếu bạn xem xét Linq , các cấu trúc quan trọng nhất cho phép Linq tồn tại có bản chất là chức năng: biểu thức lambda .

Một ví dụ khác, F #. Bạn có thể nói nó chủ yếu là FP, nhưng có nhiều khái niệm và cấu trúc OOP có sẵn. Bạn có thể định nghĩa các lớp, lớp trừu tượng, giao diện, đối phó với sự kế thừa. Bạn thậm chí có thể sử dụng khả năng biến đổi khi nó làm cho mã của bạn rõ ràng hơn hoặc khi nó tăng hiệu suất đáng kể.

Nhiều ngôn ngữ hiện đại là đa mô hình.

Đề nghị đọc

Khi tôi ở trong cùng một chiếc thuyền (nền OOP, học FP), tôi muốn gợi ý cho bạn một số bài đọc tôi thực sự đánh giá cao:


8
@duffymo: nhận xét của bạn, cách bạn đặt nó, chủ yếu là vô nghĩa. Không ai muốn so sánh ngôn ngữ, máy ảo hoặc nền tảng, cảm ơn bạn.
Bruno Reis

6
@Bruno - một phản ứng với "sức mạnh của .NET". Thư giãn.
duffymo

6
Thật buồn cười, tôi không thấy bạn theo đuổi Dykam về bình luận vô nghĩa của anh ấy. Bạn đã được đề cử làm người điều hành trong khi tôi không tìm kiếm? Không ai rực lửa ở đây ngoài bạn. Tôi sẽ nói lại lần nữa - thư giãn đi.
duffymo

4
Heh, xin lỗi nếu tôi bắt đầu một số lửa. Tôi không có ý nói các nền tảng khác kém mạnh mẽ hơn, chỉ là .NET không hỗ trợ OOP. Ví dụ, nó có tối ưu hóa cuộc gọi đuôi.
Dykam

5
@nawfal, cho đến khi bạn có thể chỉ ra một số tính năng nội tại trong hai mô hình và nói rằng chúng không tương thích, chúng là trực giao: đó là trung tâm của cuộc thảo luận. Theo định nghĩa, FP không tương thích với lập trình mệnh lệnh, nhưng OOP không giới hạn ở lập trình mệnh lệnh. Lý do chúng tôi có các từ khác nhau cho các khái niệm này là để chúng tôi có thể nói về chúng: khi bạn gộp chúng lại với nhau, bạn chỉ cần buộc chúng tôi không cần phải đưa ra các từ mới.
DavidS

31

Lập trình hướng đối tượng cung cấp:

  1. Đóng gói, để
    • kiểm soát đột biến của trạng thái nội bộ
    • giới hạn khớp nối với đại diện nội bộ
  2. Subtyping, cho phép:
    • thay thế các loại tương thích (đa hình)
    • một phương tiện thô sơ để chia sẻ thực hiện giữa các lớp (kế thừa thực hiện)

Lập trình hàm, trong Haskell hoặc thậm chí trong Scala, có thể cho phép thay thế thông qua cơ chế chung hơn của các lớp loại. Trạng thái nội bộ có thể thay đổi hoặc không được khuyến khích hoặc bị cấm. Đóng gói của đại diện nội bộ cũng có thể đạt được. Xem Haskell vs OOP để so sánh tốt.

Norman khẳng định rằng "Thêm một loại điều mới vào một chương trình chức năng có thể yêu cầu chỉnh sửa nhiều định nghĩa hàm để thêm trường hợp mới." phụ thuộc vào mức độ mã chức năng đã sử dụng các lớp loại. Nếu Kết hợp mẫu trên một Kiểu dữ liệu trừu tượng cụ thể được lan truyền khắp một cơ sở mã, bạn thực sự sẽ gặp phải vấn đề này, nhưng có lẽ đó là một thiết kế kém để bắt đầu.

EDITED Đã xóa tham chiếu đến các chuyển đổi ngầm định khi thảo luận về các lớp loại. Trong Scala, các lớp loại được mã hóa với các tham số ngầm định, không phải chuyển đổi, mặc dù chuyển đổi ngầm là một phương tiện khác để đạt được sự thay thế của các loại tương thích.


3
Máy đánh chữ không phải là một cơ chế để chuyển đổi ngầm sang các loại khác. Chúng là một mô tả về một tập hợp các hàm được xác định cho một loại để cung cấp một dạng đa hình. Thứ gần nhất từ ​​OOP kiểu Java sẽ là các giao diện, mặc dù các kiểu chữ Haskell có một số khác biệt quan trọng.
Zak

25
  1. Nếu bạn đang ở trong một môi trường đồng thời nặng nề, thì lập trình chức năng thuần túy rất hữu ích. Việc thiếu trạng thái đột biến làm cho sự tương tranh gần như không đáng kể. Xem Erlang.

  2. Trong một ngôn ngữ đa biến, bạn có thể muốn mô hình hóa một số thứ theo chức năng nếu sự tồn tại của trạng thái có thể thay đổi phải là một chi tiết triển khai và do đó, FP là một mô hình tốt cho miền vấn đề. Ví dụ, xem phần hiểu danh sách bằng Python hoặc std.range trong ngôn ngữ lập trình D. Chúng được lấy cảm hứng từ lập trình chức năng.

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.