OOP vs Lập trình chức năng so với thủ tục [đã đóng]


237

Sự khác biệt giữa các mô hình lập trình này là gì và chúng có phù hợp hơn với các vấn đề cụ thể hoặc có trường hợp sử dụng nào ưu tiên cái này hơn các trường hợp khác không?

Ví dụ kiến ​​trúc đánh giá cao!


Đây không phải là một câu trả lời đầy đủ, nhưng tôi viết một chút về cách "chức năng" ảnh hưởng / tương phản phong cách "OO" (trong ngữ cảnh của F #) ở đây: lorgonblog.spaces.live.com/blog/cns!701679AD17B6D 310!511. mục
Brian

Bạn có thể cân nhắc đọc nó! Có rất nhiều ví dụ về thời điểm sử dụng kiến ​​nào là điểm khác biệt chính, ưu / nhược điểm, v.v.
Nikita Ignatov



Chú Bob đã tweet về điều này. Và cũng ở đây .
jaco0646

Câu trả lời:


129

Tất cả chúng đều tốt theo cách riêng của chúng - Chúng đơn giản là những cách tiếp cận khác nhau cho cùng một vấn đề.

Trong một phong cách thủ tục thuần túy, dữ liệu có xu hướng tách rời khỏi các chức năng hoạt động trên nó.

Trong một phong cách hướng đối tượng, dữ liệu có xu hướng mang theo nó một tập hợp các hàm.

Trong một kiểu chức năng, dữ liệu và chức năng có xu hướng có nhiều điểm chung với nhau (như trong Lisp và Scheme) trong khi cung cấp sự linh hoạt hơn về cách các chức năng thực sự được sử dụng. Các thuật toán cũng có xu hướng được xác định theo thuật ngữ đệ quy và thành phần hơn là các vòng lặp và lặp.

Tất nhiên, bản thân ngôn ngữ chỉ ảnh hưởng đến phong cách nào được ưa thích. Ngay cả trong một ngôn ngữ chức năng thuần túy như Haskell, bạn có thể viết theo kiểu thủ tục (mặc dù điều đó rất nản lòng) và ngay cả trong ngôn ngữ thủ tục như C, bạn có thể lập trình theo kiểu hướng đối tượng (như trong GTK + và API EFL).

Để rõ ràng, "lợi thế" của mỗi mô hình chỉ đơn giản là trong việc mô hình hóa các thuật toán và cấu trúc dữ liệu của bạn. Nếu, ví dụ, thuật toán của bạn liên quan đến danh sách và cây, thuật toán chức năng có thể là hợp lý nhất. Hoặc, nếu, ví dụ, dữ liệu của bạn có cấu trúc cao, việc kết hợp nó thành đối tượng sẽ hợp lý hơn nếu đó là mô hình nguyên gốc của ngôn ngữ của bạn - hoặc, nó có thể dễ dàng được viết như một sự trừu tượng hóa chức năng của các đơn nguyên, là mô hình bản địa của các ngôn ngữ như Haskell hoặc ML.

Sự lựa chọn mà bạn sử dụng chỉ đơn giản là những gì có ý nghĩa hơn cho dự án của bạn và sự trừu tượng mà ngôn ngữ của bạn hỗ trợ.


5
Những gì bạn nói, dường như không phản ánh những gì bạn đã viết. Bạn nói rằng họ không có "ưu và nhược điểm", và sau đó nói họ là những cách tiếp cận khác nhau như thế nào. Tại sao một người nào đó chọn một cách tiếp cận khác, dựa trên bất kỳ tình huống nào? điểm mạnh và điểm yếu, ưu và nhược điểm, bất cứ điều gì bạn gọi chúng đều tồn tại! Tôi không nói rằng một người vốn đã tốt hơn, và bạn cũng không. Tôi tin rằng đó là những gì bạn thực sự đã cố gắng nói. trừ khi bạn thực sự tin rằng bất kỳ phương pháp được lựa chọn nào đều không có mặt tích cực và tiêu cực, liên quan đến sự chấp thuận khác.
JM Becker

1
@TechZilla: Tôi đồng ý rằng từ ngữ của tôi kém, nhưng ý tôi là không thực sự có một danh sách các tính năng mà bạn có thể chỉ ra và nói ngôn ngữ X tốt hơn Y mà không đủ điều kiện ngôn ngữ X phù hợp hơn với thuật toán viết U và ngôn ngữ Y có thể phù hợp hơn với việc viết thuật toán V, trong khi cả hai có thể dễ dàng thực hiện bằng một trong hai ngôn ngữ.
greyfade

2
Sự khác biệt giữa thủ tục và chức năng là không rõ ràng đối với tôi. Tôi đang học Scheme / Rackett tại College, nhưng tôi thực sự không thể thấy sự khác biệt lớn giữa nó và C hoặc PHP theo thủ tục, bạn có thể đưa ra một số ví dụ không?
Leonel

7
@Leonel: Sự khác biệt lớn nhất mà hầu hết mọi người sẽ trích dẫn là trong các ngôn ngữ thủ tục, bạn có thể sử dụng vòng lặp for, nhưng ngôn ngữ chức năng, không có điều đó - thay vào đó, bạn sử dụng các lệnh gọi đệ quy đến các hàm để thực hiện cùng một tác vụ. Các ngôn ngữ hàm cũng tạo ra các hàm đối tượng hạng nhất - bạn có thể chuyển chúng xung quanh giống như bạn làm số - nhưng bạn không thể làm điều đó trong C (và hỗ trợ của PHP cho nó bị hỏng).
greyfade

2
@tastro: Khi một mô hình có ý nghĩa hơn các mô hình khác. Đó thực sự là tất cả. Đôi khi nó có ý nghĩa hơn khi mô hình hóa mã của bạn như là thành phần của các hàm và đôi khi nó có ý nghĩa hơn khi mô hình hóa dữ liệu của bạn dưới dạng các đối tượng. Có nhiều cách để thể hiện thuật toán và cấu trúc dữ liệu. OOP và chức năng xảy ra là hai trong số những điều đó.
greyfade

25

Tôi nghĩ rằng các thư viện, công cụ, ví dụ và cộng đồng có sẵn hoàn toàn vượt qua mô hình ngày nay. Ví dụ, ML (hoặc bất cứ điều gì) có thể là ngôn ngữ lập trình đa năng cuối cùng nhưng nếu bạn không thể có được bất kỳ thư viện tốt nào cho những gì bạn đang làm thì bạn sẽ bị lừa.

Ví dụ: nếu bạn đang tạo một trò chơi video, có nhiều ví dụ mã và SDK tốt hơn trong C ++, vì vậy bạn có thể tốt hơn với điều đó. Đối với một ứng dụng web nhỏ, có một số khung công tác Python, PHP và Ruby tuyệt vời sẽ giúp bạn thoát khỏi và chạy rất nhanh. Java là một lựa chọn tuyệt vời cho các dự án lớn hơn vì các thư viện và nền tảng kiểm tra thời gian biên dịch và thời gian biên dịch.

Nó đã từng là trường hợp các thư viện tiêu chuẩn cho các ngôn ngữ khác nhau khá nhỏ và dễ dàng sao chép - C, C ++, Trình biên dịch, ML, LISP, v.v. đi kèm với những điều cơ bản, nhưng có xu hướng phát triển khi chuẩn hóa mọi thứ như truyền thông mạng, mã hóa, đồ họa, định dạng tệp dữ liệu (bao gồm cả XML), thậm chí các cấu trúc dữ liệu cơ bản như cây cân bằng và hashtables đã bị bỏ qua!

Các ngôn ngữ hiện đại như Python, PHP, Ruby và Java giờ đây đi kèm với một thư viện tiêu chuẩn tốt hơn rất nhiều và có nhiều thư viện bên thứ ba tốt mà bạn có thể dễ dàng sử dụng, nhờ một phần lớn vào việc áp dụng các không gian tên để giữ cho các thư viện không bị va chạm với nhau, và thu gom rác để chuẩn hóa các sơ đồ quản lý bộ nhớ của các thư viện.


5
Python, ruby, ... không có các thư viện "tiêu chuẩn" như C hoặc LISP, vì chúng là các ngôn ngữ thực hiện duy nhất. Python là những gì Guido nói, không có tiêu chuẩn. Bất kỳ triển khai C hoặc LISP cụ thể (hoặc bất cứ điều gì) hiện nay đều đi kèm với một bộ thư viện lớn ngoài các thư viện tiêu chuẩn.
Dan Andreatta

8
Câu hỏi là về sự khác biệt giữa lập trình hướng đối tượng, chức năng và lập trình thủ tục. Mặc dù các ngôn ngữ được đề cập trong các câu trả lời này chắc chắn cho vay theo một trong những cách tiếp cận này, câu trả lời không đề cập đến bất kỳ khái niệm nào trong số này ... Bất kể có hay không "các thư viện có sẵn [...] [Trump] mô hình", điều đó không trả lời câu hỏi trong tầm tay, do đó bước bên cạnh câu hỏi hoàn toàn hợp lệ là gì.
rinogo

1
irant liên quan đến ircmaxell
rinogo

20

Những mô hình này không phải loại trừ lẫn nhau. Nếu bạn nhìn vào python, nó hỗ trợ các hàm và các lớp, nhưng đồng thời, mọi thứ đều là một đối tượng, bao gồm các hàm. Bạn có thể trộn và kết hợp tất cả các kiểu chức năng / oop / thủ tục trong một đoạn mã.

Ý tôi là, trong các ngôn ngữ chức năng (ít nhất là trong Haskell, người duy nhất tôi đã nghiên cứu) không có tuyên bố nào! các chức năng chỉ được phép một biểu thức bên trong chúng !! NHƯNG, các chức năng là công dân hạng nhất, bạn có thể chuyển chúng xung quanh dưới dạng tham số, cùng với một loạt các khả năng khác. Họ có thể làm những việc mạnh mẽ với vài dòng mã.

Mặc dù trong ngôn ngữ thủ tục như C, cách duy nhất bạn có thể chuyển các hàm xung quanh là sử dụng các con trỏ hàm và một mình nó không cho phép nhiều tác vụ mạnh mẽ.

Trong python, một hàm là một công dân hạng nhất, nhưng nó có thể chứa số lượng câu lệnh tùy ý. Vì vậy, bạn có thể có một hàm chứa mã thủ tục, nhưng bạn có thể chuyển nó xung quanh giống như các ngôn ngữ chức năng.

Tương tự với OOP. Một ngôn ngữ như Java không cho phép bạn viết các thủ tục / hàm bên ngoài một lớp. Cách duy nhất để vượt qua một chức năng xung quanh là bọc nó trong một đối tượng thực hiện chức năng đó, và sau đó truyền đối tượng đó xung quanh.

Trong Python, bạn không có hạn chế này.


Tôi tin rằng bạn có nghĩa là "những mô hình này không cần phải loại trừ lẫn nhau". Cả ba đều trực giao trong đó lý tưởng nhất là bạn có thể sử dụng một, 2 hoặc 3 trong số chúng trong một chương trình (nếu ngôn ngữ của bạn cho phép).
Joe Pineda

Phải tôi đoán loại trừ lẫn nhau là một thuật ngữ tốt hơn cho điều đó! cảm ơn
hasen

14

Đối với GUI, tôi muốn nói rằng Nghịch lý hướng đối tượng là rất phù hợp. Cửa sổ là một Đối tượng, Hộp văn bản là Đối tượng và Nút Okay cũng vậy. Mặt khác, các công cụ xử lý chuỗi như Xử lý chuỗi có thể được thực hiện với chi phí thấp hơn nhiều và do đó đơn giản hơn với mô hình thủ tục đơn giản.

Tôi không nghĩ đó là một câu hỏi về ngôn ngữ. Bạn có thể viết chức năng, thủ tục hoặc hướng đối tượng trong hầu hết mọi ngôn ngữ phổ biến, mặc dù nó có thể là một số nỗ lực bổ sung trong một số.


17
Bị cám dỗ downvote vì đã duy trì quan niệm sai lầm rằng "Object = GUI widget", nhưng tôi sẽ kiềm chế. OOP cũng hoạt động tốt để biểu diễn các khái niệm trừu tượng, chẳng hạn như "UserAccount" hoặc "PendingSale", như đối với các thành phần giao diện hiển thị như "Cửa sổ" và "Nút".
Dave Sherohman

5
Tôi đã viết rằng một cửa sổ có thể là một đối tượng. Làm thế nào để bạn rút ra kết luận rằng mọi Đối tượng là một cửa sổ từ đó? Đó chỉ là một ví dụ. Tất nhiên OOP cũng có thể được sử dụng để mô hình hóa các thực thể trừu tượng và mối quan hệ của chúng. Dù sao, cảm ơn vì đã không xuống cấp. Dù sao tôi cũng không có nhiều điểm: D
panschk

6
-1. OOP không liên quan gì đến GUI. Lý tưởng nhất, phương pháp tốt nhất để thiết kế guis là sử dụng tệp văn bản bên ngoài (ví dụ HTML). Trong khi những thứ như xử lý chuỗi thực sự được thực hiện tốt hơn nhiều với các đối tượng. (nghĩ về chuỗi trong C) !!
hasen

1
Tôi không biết, có lẽ tôi chỉ quen lập trình với các đối tượng để nhận ra điều đó. Nhưng làm thế nào bạn có thể thực hiện một số công cụ tương tác như thay đổi giá trị trong TextBox X khi giá trị của TextBox Y đã bị thay đổi mà không sử dụng các đối tượng? Được rồi, bạn chỉ có thể sử dụng bình toàn cầu cho mọi thứ ...
panschk

1
Xử lý chuỗi được thực hiện một cách khủng khiếp bằng perl (tốt hơn 100 lần so với Java, C ++ hoặc C #) nhưng chức năng chuỗi của ngôn ngữ hoàn toàn KHÔNG hướng đối tượng. Xử lý chuỗi của C rất tệ, nhưng sau đó C không phải là ngôn ngữ thủ tục duy nhất (cũng không phải là ngôn ngữ tốt nhất).
Joe Pineda

6

Để trả lời câu hỏi của bạn, chúng tôi cần hai yếu tố:

  1. Hiểu biết về các đặc điểm của phong cách / mẫu kiến ​​trúc khác nhau.
  2. Hiểu biết về các đặc điểm của các mô hình lập trình khác nhau.

Một danh sách các kiểu / kiểu kiến ​​trúc phần mềm được hiển thị trên bài viết kiến ​​trúc phần mềm trên Wikipeida. Và bạn có thể nghiên cứu về chúng một cách dễ dàng trên web.

Tóm lại và nói chung, Thủ tục là tốt cho một mô hình tuân theo quy trình, OOP tốt cho thiết kế và Functional tốt cho lập trình cấp cao.

Tôi nghĩ bạn nên thử đọc lịch sử trên mỗi mô hình và xem tại sao mọi người tạo ra nó và bạn có thể hiểu chúng một cách dễ dàng.

Sau khi hiểu cả hai, bạn có thể liên kết các mục của kiểu / mẫu kiến ​​trúc với mô hình lập trình.


2

Tôi nghĩ rằng chúng thường không "so với", nhưng bạn có thể kết hợp chúng. Tôi cũng nghĩ rằng thông thường, những từ bạn đề cập chỉ là từ thông dụng. Có rất ít người thực sự biết "hướng đối tượng" nghĩa là gì, ngay cả khi họ là những nhà truyền giáo khốc liệt nhất của nó.


1

Một người bạn của tôi đang viết một ứng dụng đồ họa bằng NVIDIA CUDA . Ứng dụng phù hợp rất tốt với mô hình OOP và vấn đề có thể được phân tách thành các mô-đun gọn gàng. Tuy nhiên, để sử dụng CUDA, bạn cần sử dụng C, không hỗ trợ kế thừa . Do đó, bạn cần phải khéo léo.

a) Bạn nghĩ ra một hệ thống thông minh sẽ mô phỏng sự kế thừa ở một mức độ nhất định. Nó có thể được thực hiện!

i) Bạn có thể sử dụng hệ thống hook , mong muốn mọi đứa trẻ C của cha mẹ P có một ghi đè nhất định cho chức năng F. Bạn có thể khiến trẻ đăng ký phần ghi đè của chúng, sẽ được lưu trữ và gọi khi được yêu cầu.

ii) Bạn có thể sử dụng tính năng căn chỉnh bộ nhớ cấu trúc để đưa trẻ em vào cha mẹ.

Điều này có thể gọn gàng nhưng không dễ để đưa ra giải pháp đáng tin cậy trong tương lai. Bạn sẽ dành nhiều thời gian để thiết kế hệ thống và không có gì đảm bảo rằng bạn sẽ không gặp phải vấn đề nửa chừng trong dự án. Thực hiện nhiều kế thừa thậm chí còn khó hơn, nếu không muốn nói là gần như không thể.

b) Bạn có thể sử dụng chính sách đặt tên nhất quán và sử dụng phương pháp phân chia và chinh phục để tạo chương trình. Nó sẽ không có bất kỳ sự kế thừa nào nhưng vì các chức năng của bạn nhỏ, dễ hiểu và được định dạng nhất quán nên bạn không cần nó. Số lượng mã bạn cần viết tăng lên, rất khó để tập trung và không chịu thua các giải pháp dễ dàng (hack). Tuy nhiên, cách mã hóa ninja này là cách mã hóa C. Giữ cân bằng giữa tự do cấp thấp và viết mã tốt. Cách tốt để đạt được điều này là viết nguyên mẫu bằng ngôn ngữ chức năng. Ví dụ, Haskell cực kỳ tốt cho các thuật toán tạo mẫu.

Tôi có xu hướng tiếp cận b. Tôi đã viết một giải pháp khả thi bằng cách sử dụng phương pháp a, và tôi sẽ thành thật, nó cảm thấy rất không tự nhiên khi sử dụng mã đó.


Các trình đồng bộ c ++ đầu tiên không có gì khác hơn các bộ xử lý trước tạo mã C. Như vậy, TẤT CẢ các tính năng của c ++ - bao gồm nhiều kế thừa, có thể được triển khai bằng C. (mô phỏng xử lý ngoại lệ c ++ trong C sẽ yêu cầu một số loại hỗ trợ nền tảng cho các ngoại lệ, nhưng việc triển khai c ++ cũng yêu cầu điều đó, vì vậy tôi không nghĩ rằng nó làm cơ bản ý tưởng không hợp lệ).
Chris Becke

2
@Chris Trở thành câu trả lời của bạn quá triết lý. Đối với một, C có nhiều tiêu chuẩn (qua nhiều năm), hầu như không có bất kỳ trong số chúng được chấp nhận hoàn toàn bởi trình biên dịch C chứ đừng nói đến c ++. Có thể nói, C ++ là siêu bộ của C vì nó sử dụng cú pháp C không có nghĩa gì nhiều vì bạn thậm chí không thể viết mã cho một trình biên dịch C biên dịch trong trình biên dịch C khác mà không cần nỗ lực đáng kể. Hơn nữa, có các tính năng ngôn ngữ (hệ thống loại, hỗ trợ OOD) được cung cấp bằng các ngôn ngữ khác không thể thực hiện bằng C mà không sử dụng C để thiết kế ngôn ngữ mới (đó chính xác là lý do tại sao có 'ngôn ngữ mới')
Sprague

Bạn biết. Tôi không thể thấy bất kỳ sự liên quan nào mà bình luận của tôi có liên quan đến bài viết này cả. : P
Chris Becke

Cuda đã hỗ trợ C ++ một thời gian rồi.
Aryeh Leib Taurog
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.