Thiết kế trong ngôn ngữ hỗn hợp của người Viking: thiết kế hướng đối tượng hoặc lập trình chức năng?


11

Trong vài năm qua, các ngôn ngữ tôi muốn sử dụng ngày càng trở nên "chức năng" hơn. Bây giờ tôi sử dụng các ngôn ngữ là một loại "lai": C #, F #, Scala. Tôi thích thiết kế ứng dụng của mình bằng các lớp tương ứng với các đối tượng miền và sử dụng các tính năng chức năng trong đó điều này giúp mã hóa dễ dàng hơn, trùng khớp hơn và an toàn hơn (đặc biệt là khi hoạt động trên các bộ sưu tập hoặc khi truyền chức năng).

Tuy nhiên, hai thế giới "đụng độ" khi đến với các mẫu thiết kế. Ví dụ cụ thể mà tôi phải đối mặt gần đây là mẫu Observer. Tôi muốn nhà sản xuất thông báo cho một số mã khác ("người tiêu dùng / người quan sát", giả sử bộ lưu trữ DB, bộ ghi, v.v.) khi một mục được tạo hoặc thay đổi.

Ban đầu tôi đã làm nó "chức năng" như thế này:

producer.foo(item => { updateItemInDb(item); insertLog(item) })
// calls the function passed as argument as an item is processed

Nhưng bây giờ tôi đang tự hỏi liệu tôi có nên sử dụng cách tiếp cận "OO" hơn không:

interface IItemObserver {
  onNotify(Item)
}
class DBObserver : IItemObserver ...
class LogObserver: IItemObserver ...

producer.addObserver(new DBObserver)
producer.addObserver(new LogObserver)
producer.foo() //calls observer in a loop

Đó là pro và con của hai cách tiếp cận? Tôi đã từng nghe một chuyên gia về FP nói rằng các mẫu thiết kế chỉ tồn tại vì những hạn chế của ngôn ngữ và đó là lý do tại sao có rất ít ngôn ngữ chức năng. Có lẽ đây có thể là một ví dụ về nó?

EDIT: Trong kịch bản cụ thể của tôi, tôi không cần nó, nhưng .. bạn sẽ thực hiện loại bỏ và thêm "quan sát viên" theo cách chức năng như thế nào? (Tức là làm thế nào bạn sẽ thực hiện tất cả các chức năng trong mẫu?) Chỉ cần chuyển một chức năng mới, ví dụ?


Diễn viên thì sao?
kiritsuku

Hãy quên đi các lớp học và tất cả những thứ vô dụng OOPish. Thay vào đó, bạn nên suy nghĩ về các mô-đun (xem ngôn ngữ SML và OCaml để tìm cảm hứng).
SK-logic

@Antoras Nếu bạn có thể so sánh với cách tiếp cận dựa trên Diễn viên, thì sẽ được chào đón nhiều hơn :)
Lorenzo Dematté

2
@ dema80, OCaml hoàn toàn đa mô hình. Các mô-đun không liên quan đến lập trình chức năng nào cả. Có một hệ thống mô-đun tiên tiến trong một Ada hoàn toàn bắt buộc, ví dụ. Và tất cả danh tiếng mà OOP có được thực sự nên chuyển sang các mô-đun - tất cả những điều tốt đẹp trong OOP chỉ là các hình thức mô phỏng chức năng mô-đun khác nhau. Bạn có thể quên hoàn toàn tất cả các lớp đó và sử dụng cú pháp của chúng để thể hiện các mô-đun thay vào đó, suy nghĩ về các mô-đun, chứ không phải OOP. Btw., Đó chính xác là những gì Microsoft đã làm với mscorlib của họ - không có nhiều OOP ở đó, chỉ có các mô-đun và không gian tên.
SK-logic

1
Tôi nghĩ rằng câu hỏi tốt hơn là "Có sự rõ ràng hoặc tổ chức nào bạn mất bằng cách thực hiện theo cách của FP không?"
djechlin

Câu trả lời:


0

Đó là một ví dụ điển hình về hai cách tiếp cận khác nhau mang khái niệm thực hiện một nhiệm vụ bên ngoài ranh giới quan tâm đối với đối tượng gọi.

Mặc dù trong ví dụ này rõ ràng rằng bạn nên sử dụng phương pháp tiếp cận chức năng, nói chung, nó sẽ thực sự phụ thuộc vào mức độ phức tạp của hành vi mà đối tượng được gọi phải thể hiện. Nếu đó thực sự là một vấn đề của hành vi phức tạp, nơi bạn sẽ thấy mình thường xuyên áp dụng logic tương tự và các trình tạo hàm không thể được sử dụng để diễn đạt rõ ràng, thì có lẽ bạn sẽ muốn đi theo thành phần lớp hoặc kế thừa, nơi bạn sẽ có thêm một chút tự do để sử dụng lại và mở rộng hành vi hiện có trên cơ sở đặc biệt.

Tuy nhiên, một mô hình mà tôi đã quan sát được là các nhà phát triển thường sử dụng phương pháp tiếp cận chức năng ban đầu và chỉ khi nhu cầu về hành vi chi tiết hơn phát sinh, họ quyết định đi theo cách tiếp cận dựa trên lớp. Tôi biết, chẳng hạn, Django đã chuyển từ các chế độ xem dựa trên chức năng, trình tải mẫu và người chạy thử nghiệm sang các chế độ dựa trên lớp một khi lợi ích và yêu cầu trở nên rõ ràng, nhưng không phải trước đó.


Tôi nghĩ rằng câu trả lời này là một chút sai lầm. Lập trình chức năng không phải là lập trình (chỉ với) chức năng. Lập trình hàm cũng sử dụng trừu tượng, vì vậy không có sự phân đôi ở đây.
Doval

"Thành phần hoặc thừa kế, nơi bạn sẽ có thêm một chút tự do để tái sử dụng và mở rộng hành vi hiện có" bạn đang nói như thế này KHÔNG phải là một trong những lợi ích cốt lõi của FP thuần túy. tính mô đun, khả năng kết hợp và khả năng sử dụng lại chỉ xảy ra một cách tự nhiên khi bạn viết mã theo chức năng, đây không phải là "điều OOP"
sara

@ FilipDupanović Tôi đã đề cập đến việc sử dụng lại và mở rộng mã hiện có. các hàm thuần túy có lẽ là những thứ có thể kết hợp nhất trong tất cả các chương trình. bạn đã viết như thể bạn không thể quản lý sự phức tạp trong một môi trường chức năng thuần túy. quản lý sự phức tạp bằng cách kết hợp các phần đơn giản thành các phần lớn hơn nhưng vẫn đơn giản và mờ đục là toàn bộ cốt lõi của FP, và nhiều người sẽ cho rằng nó thậm chí còn tốt hơn OOP. Tôi không đồng ý với sự phân đôi giữa "lớp lót chức năng không chia tỷ lệ OOP rắn mà không có vấn đề gì" mà bạn đưa ra.
sara

bạn đã nói rằng FP kém hơn khi soạn thảo và sử dụng lại mã, và khi các ứng dụng phát triển phức tạp hơn, OOP sẽ ít nhiều luôn luôn "tốt hơn". Tôi khẳng định điều này chỉ đơn giản là sai và gây hiểu lầm, và vì vậy tôi nghĩ rằng nó đã bảo đảm một downvote. Đó thực sự là "nhiệt tâm thuần túy"? Tôi sẽ không thảo luận thêm về vấn đề này ở đây vì các ý kiến ​​không dành cho các cuộc thảo luận mở rộng như thế này.
sara

5

Phiên bản chức năng ngắn hơn nhiều, dễ bảo trì, dễ đọc hơn và nói chung, vượt trội hơn rất nhiều về mọi khía cạnh có thể tưởng tượng được.

Mặc dù vậy, nhiều thứ khác xa so với tất cả các mẫu để bù đắp cho việc thiếu các tính năng trong OOP, chẳng hạn như Người quan sát. Đó là những mô hình tốt hơn nhiều chức năng.


Tôi đồng ý và có cùng cảm giác.
Lorenzo Dematté

Tôi đồng ý và có cùng cảm giác. Nhưng tôi đã "gian lận" với mã chức năng của mình: trong trường hợp của tôi là tất cả những gì tôi cần, nhưng nếu tôi cần thêm và xóa "quan sát viên" thì sao? Tôi đã chỉnh sửa câu hỏi của mình
Lorenzo Dematté

5

"Guru guru" của bạn là một phần đúng; nhiều mẫu OO là hack để làm những việc chức năng. (Ông cho rằng đây là lý do có ít ngôn ngữ FP có vẻ không rõ ràng nhất.) Các mẫu Quan sát và Chiến lược đang cố gắng mô phỏng các chức năng hạng nhất. Mẫu khách truy cập là một bản hack để mô phỏng khớp mẫu. Của bạn IItemObserverchỉ là một chức năng trong ngụy trang. Giả vờ nó khác với bất kỳ chức năng nào khác có một mặt hàng không mua cho bạn bất cứ thứ gì.

Đối tượng chỉ là một loại trừu tượng dữ liệu. Bài viết này sẽ giúp làm sáng tỏ chủ đề đó. Các đối tượng có thể hữu ích, nhưng điều quan trọng là phải nhận ra chúng không phù hợp với mọi thứ. Không có sự phân đôi; chỉ đơn giản là vấn đề chọn công cụ phù hợp cho công việc phù hợp và lập trình chức năng không có cách nào yêu cầu bạn từ bỏ các đối tượng. Điều đó sang một bên, lập trình chức năng không chỉ là sử dụng các chức năng. Đó cũng là về việc giảm thiểu tác dụng phụ và đột biến.


+1 cho (IMO) một câu trả lời hay. Ngoài ra, cảm ơn vì liên kết đến bài báo: Tôi đã đọc nó một thời gian trước và sau đó mất nó. Bây giờ tôi đã tìm thấy nó một lần nữa.
Giorgio

-1

Tôi thực sự không thể trả lời câu hỏi vì tôi không giỏi ngôn ngữ chức năng; nhưng tôi nghĩ bạn nên ít quan tâm đến cách tiếp cận miễn là những gì bạn có hiệu quả. Theo những gì tôi hiểu, miễn là bạn không thêm nhiều người nghe trong tương lai hoặc không thay đổi người nghe trong khi thực hiện, bạn rất có thể bỏ qua mẫu Người quan sát ở đây.

Tôi không đồng ý rằng các mẫu thiết kế tạo nên "hạn chế" trong các ngôn ngữ OO. Họ ở đó để sử dụng tốt các tính năng OOP. Đa hình và kế thừa là các tính năng, không giới hạn. Các mẫu thiết kế sử dụng các tính năng này để thúc đẩy thiết kế linh hoạt. Bạn có thể tạo một chương trình hoàn toàn không phải OO trong OO. Bạn có thể, rất cẩn thận, viết toàn bộ chương trình chứa các đối tượng không có trạng thái, bắt chước FP.


1
"Bạn có thể, với rất nhiều sự quan tâm, viết toàn bộ chương trình có chứa các đối tượng không có trạng thái, bắt chước FP.", Tất nhiên, và thông qua kỷ luật bạn cũng có thể làm điều tương tự bằng các ngôn ngữ mệnh lệnh. :) Nói chung, tôi không nghĩ tại các thiết kế vỗ về là một cái gì đó để bù đắp cho những hạn chế, nhưng hãy xem xét trường hợp của mẫu Khách truy cập ..
Lorenzo Dematté

Ngoài ra, tôi không quan tâm đến mã: tuy nhiên, tôi muốn đối đầu với các lập trình viên đồng nghiệp về cách tiếp cận (theo hiểu biết của tôi, đây là những gì lập trình viên. Nếu không, tôi sẽ đăng Q của mình lên SO)
Lorenzo Dematté

Mỗi khi bạn phát hiện ra một mẫu lặp lại, nó không là gì ngoài một dấu hiệu cho thấy sự hạn chế nghiêm trọng của ngôn ngữ và khung mô hình của bạn. Sẽ không có mô hình nào trong một thế giới lý tưởng.
SK-logic

@ SK-logic: Thật không may, thế giới không lý tưởng và thế giới thực có mô hình. Đó là lý do tại sao các ngôn ngữ OO có sự kế thừa, để triển khai mã lặp lại mà không phải viết lại chúng một lần nữa. Đối tượng thế giới thực sự có trạng thái, đó là lý do tại sao có một mẫu Trạng thái
DPD

1
@ SK-logic: Tôi biết rõ rằng một số ngôn ngữ có thể lập trình được và một số ngôn ngữ cũng cho phép thực thi các hiệu ứng từ hệ thống loại. Quan điểm của tôi là, như "OOP", "mẫu" là một thuật ngữ bị hiểu lầm đáng buồn. Một mô hình là một cái gì đó tiếp tục xuất hiện trở lại trong các hình thức tương tự nhưng khác nhau , không thừa nhận một giải pháp thống nhất . Đôi khi bạn có thể làm cho các quasirepetitions biến mất - multimethods làm cho Khách truy cập / công văn đôi trở nên dư thừa. Điều đó không có nghĩa là "tất cả các mô hình là dấu hiệu của sự thiếu hụt", bởi vì điều đó có nghĩa là thế giới thực bị thiếu. Các mẫu có nguồn gốc trong kiến trúc , không phải phần mềm.
Frank Shearar
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.