OOP trở nên dễ dàng hay khó hơn? [đóng cửa]


36

Khi các khái niệm về lập trình hướng đối tượng được giới thiệu cho các lập trình viên từ nhiều năm trước, nó có vẻ thú vị và lập trình sạch hơn. OOP là như thế này

Stock stock = new Stock();
stock.addItem(item);
stock.removeItem(item);

Điều đó dễ hiểu hơn với tên tự mô tả.

Nhưng giờ đây, OOP, với mô hình như Đối tượng truyền dữ liệu, Đối tượng giá trị, Kho lưu trữ, Tiêm phụ thuộc, v.v., đã trở nên phức tạp hơn. Để đạt được những điều trên, bạn có thể phải tạo một số lớp (ví dụ: trừu tượng, nhà máy, DAO, v.v.) và Thực hiện một số giao diện

Lưu ý: Tôi không chống lại các thực tiễn tốt nhất giúp Cộng tác, Kiểm tra và Tích hợp dễ dàng hơn


23
Tạo ra một kiến ​​trúc phần mềm tốt luôn luôn khó khăn và sẽ (rất có thể) luôn luôn như vậy.
johannes

6
Tôi sẽ đổi tên addItemcho addremoveItemcho remove. Bởi vì nó dễ đọc hơn. stock.add(item)hoặc stock.remove(item). Và định hướng OOP nhiều hơn.
razpeitia

1
OOP ban đầu trông gần như không có gì giống như những gì bạn đã thể hiện. OOP không phải là về cú pháp , đó là về một loại trừu tượng phổ biến bởi Smalltalk. Điều này không nhất thiết chứng minh quan điểm của bạn sai, cũng không phải là tiền đề thiếu sót; đúng hơn, nó thậm chí còn đúng hơn bạn nghĩ.
Konrad Rudolph

1
bạn đang so sánh táo và cam, theo logic của bạn, thì lập trình bắt buộc (tức là các vòng lặp và if-condition) đơn giản hơn tất cả những thứ chúng ta có ngày nay. Lập trình mệnh lệnh là các khối xây dựng cho các lớp / OOP và các lớp / OOP là các khối xây dựng cho các mẫu thiết kế. Mọi thứ trở nên phức tạp hơn khi bạn tiến bộ vì bạn đang giải quyết các vấn đề phức tạp hơn.
Lie Ryan

2
@LieRyan - Tôi đã thấy các vấn đề trở nên phức tạp chỉ vì không ai chịu trách nhiệm có thể giải quyết chúng bằng lập trình mệnh lệnh đơn giản và tấn công chúng bằng các mẫu thiết kế trên OOP trên giải pháp mệnh lệnh đơn giản nên được thực hiện một mình.
mouviciel

Câu trả lời:


35

Bản thân OOP đã không thay đổi nhiều kể từ khi thành lập. Một vài góc độ mới cho nó đã được khám phá, nhưng các nguyên tắc cốt lõi vẫn giống nhau. Nếu bất cứ điều gì, kiến ​​thức tập thể được thu thập qua nhiều năm làm cho cuộc sống của lập trình viên dễ dàng hơn thay vì khó khăn hơn. Các mẫu thiết kế không phải là một trở ngại; họ cung cấp một hộp công cụ giải pháp cho các vấn đề tiêu chuẩn, được chắt lọc từ nhiều năm và nhiều năm kinh nghiệm.

Vậy tại sao bạn nhận thấy OOP ngày nay phức tạp hơn so với khi bạn bắt đầu sử dụng nó?

Một lý do có thể là mã bạn đang tiếp xúc trở nên phức tạp hơn - không phải vì OOP trở nên phức tạp hơn, mà bởi vì bạn đã tiến lên nấc thang học tập và đọc các cơ sở mã lớn hơn và phức tạp hơn.

Một lý do khác có thể là trong khi mô hình phức tạp không thay đổi, kích thước và độ phức tạp của một dự án phần mềm trung bình rất có thể có. Với sức mạnh xử lý có sẵn trên các điện thoại di động cấp khách hàng từng là giấc mơ ướt của nhà phát triển trên máy chủ cách đây chưa đầy hai thập kỷ, công chúng nói chung về cơ bản mong đợi GUI hoạt hình mượt mà cho ứng dụng vứt bỏ rẻ nhất và máy tính để bàn cấp thấp mạnh hơn so với "siêu máy tính" năm 1980, chỉ có điều tự nhiên là thanh này đã được nâng lên từ những ngày đầu của Smalltalk và C ++.

Và sau đó, có một thực tế là trong các ứng dụng hiện đại, đồng thời và song song là chuẩn mực chứ không phải là ngoại lệ, và các ứng dụng thường cần phải giao tiếp giữa các máy khác nhau, xuất ra và phân tích toàn bộ sở giao thức. Mặc dù OOP là một mô hình tổ chức tuyệt vời, nhưng nó cũng có những hạn chế của nó, giống như bất kỳ mô hình nào khác: ví dụ, nó không cung cấp nhiều sự trừu tượng cho đồng thời (hầu hết các triển khai đều ít nhiều được đưa ra ngoài hoặc hoàn toàn cho các thư viện) và đó không phải là cách tiếp cận tốt nhất có thể để xây dựng trình phân tích cú pháp và chuyển đổi dữ liệu. Lập trình hiện đại thường xuyên gặp phải những hạn chế của mô hình OOP và các mẫu thiết kế chỉ có thể đưa bạn đến nay. (Cá nhân, Tôi coi thực tế là chúng ta cần các mẫu thiết kế là một dấu hiệu của điều này - nếu mô hình cung cấp các giải pháp này vượt trội, nó sẽ có ý nghĩa hơn đối với các vấn đề này và các giải pháp tiêu chuẩn sẽ rõ ràng. Không có mẫu thiết kế để mô tả kế thừa phương thức, bởi vì nó là một tính năng cốt lõi của OOP; nhưng có một Mô hình Nhà máy, vì OOP không cung cấp một cách tự nhiên rõ ràng để xây dựng các đối tượng đa hình và trong suốt.)

Bởi vì điều này, hầu hết các ngôn ngữ OOP hiện đại kết hợp các tính năng từ các mô hình khác, khiến chúng trở nên biểu cảm hơn và mạnh mẽ hơn, nhưng cũng phức tạp hơn. C # là ví dụ điển hình cho việc này: nó có nguồn gốc OOP rõ ràng, nhưng các tính năng như đại biểu, sự kiện, suy luận kiểu, kiểu dữ liệu biến thể, thuộc tính, hàm ẩn danh, biểu thức lambda, tổng quát, v.v., bắt nguồn từ các mô hình khác, đáng chú ý nhất là Lập trình hàm .


Vì vậy, các mẫu thiết kế thêm sự phức tạp. Có nghĩa là các mẫu thiết kế không nhất thiết phải là OOP mà được thêm vào để tăng cường OOP.
tunmise fasipe

@tunmisefasipe: Không hẳn. Các mẫu thiết kế chỉ là giải pháp đã được chứng minh cho các vấn đề tiêu chuẩn; chúng không phải là một 'bổ sung' cho OOP, mà là một hệ quả. Sự phức tạp đã có sẵn; mẫu thiết kế chỉ cung cấp các chiến lược sách nấu ăn để giải quyết nó.
tdammers

17

Không, nó trở nên quá kỹ thuật. Và bạn nói đúng trong cuộc trò chuyện SO C ++, chúng tôi thường nói đùa về AbstractSingletonFactoryProxyBeanBridgeAd ModuleQuản lý mà chúng ta thấy trong mã Java.

Nhưng mã tốt không thể hiện tài sản này. Trong mã tốt, bạn vẫn có thể nói

std::stack<int> s;
s.push(5);
s.pop();

4
Không rõ ràng từ bài viết của bạn, nhưng tôi nghĩ rằng kỹ thuật quá mức là rõ ràng trong cả mã Java C ++. Bản thân nó không phải là tài sản của ngôn ngữ, nhưng thực tế của các lập trình viên ... Cả hai ngôn ngữ đều cho phép viết mã tốt, mặc dù (IMO) không đặc biệt phù hợp với nó :) Các khung trong Java thật đáng tiếc.
Andres F.

12
Nói về kỹ thuật quá mức, chủ đề này là bắt buộc: thảo luận.joelonsoftware.com/default.asp?joel.3.219431
Bảo mật

3
@AresresF. đúng, nhưng dường như bạn không nhận được quá nhiều mã đó trong mã C ++, trong khi bạn làm bằng Java và .NET: chỉ cần nhìn vào mẫu thiết kế MVVMVMMD msdn.microsoft.com/en-us/magazine/hh965661.aspx như một ví dụ về cách bạn lấy 'mã đơn giản' và đặt một mẫu thiết kế lên nó để làm cho nó trông 'dễ dàng hơn' và sau đó tát một mẫu thiết kế khác trên mẫu thiết kế vì mẫu ban đầu không đơn giản như quảng cáo. Quá kỹ thuật đang ngày càng trở nên phổ biến.
gbjbaanb

5
Tôi sẽ tranh luận với bit "trở thành". Kỹ thuật quá mức là cũ như kỹ thuật.
Gort Robot

4
@AresresF. Chúng tôi đặc biệt chống Java trong trò chuyện nhưng đúng là Java, hơn cả C ++ , khuyến khích kỹ thuật quá mức vì nó làm cho nó có giá cả phải chăng hơn (GC) và các thư viện Java doanh nghiệp phổ biến đã phổ biến phong cách này, như bạn đã lưu ý bản thân bạn.
Konrad Rudolph

10

Tôi muốn nói rằng các vấn đề với "sự phức tạp" mà bạn đề cập không liên quan gì đến OOP. Nó có nhiều hơn để làm với các mối quan tâm riêng biệt.

Nhiều năm trước tôi đã làm việc trên một hệ thống, trong đó lớp miền có trách nhiệm tự tải từ cơ sở dữ liệu, vd

var userId = Request.QueryString["UserID"].ToInt();
var user = new User(userId);
user.Name = ...;
...
user.Save();

Đây là mã rất rõ ràng. Không có vấn đề trong việc hiểu điều này. Tuy nhiên, vấn đề sẽ nằm ở đơn vị kiểm tra mã. Cụ thể, làm thế nào tôi đơn vị kiểm tra Userlớp mà không phải tải một từ cơ sở dữ liệu? Và làm cách nào để kiểm tra mã xử lý yêu cầu web này mà không cần truy cập vào cơ sở dữ liệu? Nó chỉ đơn giản là không thể.

Đó là lý do tại sao chúng ta có một mẫu giống như một kho lưu trữ, để tách trách nhiệm xử lý logic miền khỏi người dùng khỏi chức năng thực sự tải và lưu một mẫu trong kho lưu trữ dữ liệu. IOC giúp giảm khớp nối, cũng làm cho mã dễ kiểm tra hơn, v.v.

Vì vậy, nếu chúng ta quay lại ví dụ bạn viết, bạn sẽ làm gì với cổ phiếu sau khi bạn tạo nó? Lưu nó trong cơ sở dữ liệu

Stock stock = new Stock();
stock.addItem(item);
stock.removeItem(item);
this.StockRepository.Add(stock);

Thế là xong! Không có sự chuyển động nào trong quá trình tiến triển của OOP cho thấy rằng nó sẽ khó hơn nữa. Thật không may, nếu bạn chọn sử dụng trình ánh xạ OR cho mã truy cập dữ liệu của mình, bạn có thể gặp phải vấn đề mà trình ánh xạ OR đang đặt ra các hạn chế về cách bạn có thể viết hệ thống của mình. Nhưng đó là một vấn đề khác.

Nếu bạn chưa quen với các mẫu này, bạn có thể yêu cầu học một phong cách lập trình mới. Nhưng phong cách lập trình đó không khó hơn lập trình OOP cũ.


Bạn biết những nỗ lực bạn phải làm để thiết lập kho lưu trữ của bạn. Mặc dù sau khi thiết lập nó, nó trở nên có thể tái sử dụng.
tunmise fasipe

có lẽ vấn đề là với thử nghiệm đơn vị, nếu chúng ta có các công cụ tốt hơn để kiểm tra toàn bộ (như bạn phải làm thế nào) thay vì các mảnh nhỏ, chúng ta sẽ có các hệ thống có ít lỗi hơn?
gbjbaanb

2
@gbjbaanb: chúng tôi đã có cái đó, nó được gọi là thử nghiệm tích hợp / chức năng. Thử nghiệm đơn vị phục vụ một mục đích khác nhau nhưng không kém phần cần thiết
Kevin

@gbjbaanb - Chúng tôi đã có các công cụ tuyệt vời để thử nghiệm trên toàn hệ thống / chấp nhận, ví dụ: Cucumber trên nền tảng Rails. Nhưng các đội thực sự giỏi và viết rất ít lỗi, nhưng cũng cung cấp nhanh, họ viết rất nhiều bài kiểm tra đơn vị, và chỉ một vài bài kiểm tra trên toàn hệ thống. Xem về "Tam giác thử nghiệm", ví dụ tại đây jonkruger.com/blog/2010/02/08/the-automated-testing-trigin
Pete

4

Cũng không. Vấn đề của chúng tôi chưa thực sự thay đổi; thanh mã được chấp nhận đã được nâng lên.

Để đạt được những điều trên, bạn có thể phải tạo một số lớp (ví dụ: trừu tượng, nhà máy, DAO, v.v.) và Thực hiện một số giao diện

Bạn không cần phải làm điều đó. Nhưng nếu bạn không gặp vấn đề thì hãy trồng trọt; những vấn đề luôn luôn tồn tại Bây giờ mặc dù, các lập trình viên có đủ kinh nghiệm làm việc đó để xác định những vấn đề đó và cung cấp các cơ chế để giảm bớt chúng (nếu cần). Chúng tôi tìm hiểu thêm về những điều đó và đưa ra các giải pháp tốt hơn (xem - quan điểm của các lập trình viên về singleton chẳng hạn).

Nhưng bạn cũng phải nhận ra rằng việc giới thiệu các lập trình viên cho OO (hoặc bất cứ điều gì cho vấn đề đó) sẽ có xu hướng bóng bẩy trong các trường hợp đặc biệt. Đơn giản là dễ dàng hơn để giải thích con đường hạnh phúc và lo lắng về phần còn lại một khi những người mới bắt đầu có được điều đó. Không có viên đạn bạc; Vì vậy, yeah, tôi cho rằng mọi thứ sẽ luôn luôn có vẻ khó khăn hơn khi mà ảo tưởng bình dị được chia ...


3

Các ví dụ "giới thiệu về OO" đơn giản hơn nhiều so với ứng dụng trong thế giới thực. Bạn chỉ cần một lớp để đạt được những điều trên. Vấn đề là nó không làm được gì nhiều. Một số mẫu thiết kế cố gắng đến gần (như ActiveRecord.) Nhưng cuối cùng, bất kỳ ví dụ nào không tầm thường sẽ có nhiều hơn một lớp; được thôi.


Cũng lưu ý rằng các khung xây dựng theo thời gian. Vì vậy, có, lập trình không đòi hỏi nhiều kiến ​​thức. Nó cũng có nghĩa là người ta có thể làm nhiều hơn trong thời gian ngắn hơn.
Jeanne Boyarsky

3

Các ngôn ngữ lập trình sử dụng OO ngày nay đang cố gắng phục vụ cho các yêu cầu và môi trường phức tạp luôn thay đổi. OO cho phép những người áp dụng của nó che giấu nhiều mức độ phức tạp (trong số các tính năng khác) để mã hóa trở nên rõ ràng hơn và dễ xây dựng và dễ hiểu hơn. Tuy nhiên, tính năng này không phải lúc nào cũng nằm ngoài khả năng này. Trong ví dụ của bạn, OO đã cho phép bạn ẩn một số chi tiết với tôi bằng cách cung cấp phương thức để quản lý các mục trong bộ sưu tập và thậm chí có thể duy trì nó bằng phương pháp "AddItem". Chi tiêu nỗ lực trong việc che giấu sự phức tạp có thể dẫn đến một cách dễ sử dụng và một khuôn khổ có thể sử dụng lại làm cho cuộc sống đơn giản hơn. Ví dụ, nhiều triển khai ORM cho phép bạn giao tiếp với cơ sở dữ liệu mà không cần lập trình viên viết chi tiết SQL. Điều này thực sự mạnh mẽ và làm cho nó đơn giản hơn trên nhà phát triển.

Các mẫu bạn đề cập đến chỉ có vậy. Họ được cho là để làm cho cuộc sống của bạn dễ dàng hơn. Nhưng nó là tùy thuộc vào bạn để áp dụng chúng và điều chỉnh chúng. Thực tế là cần nhiều công việc hơn chỉ vì bạn đạt được nhiều lợi ích hơn. Nó giống như trả nhiều tiền hơn cho một chiếc Ferrari. Nếu bạn muốn các tính năng bổ sung, bạn phải trả tiền cho họ. Vì vậy, nếu bạn quyết định xây dựng một giải pháp N-Tier có thể mở rộng có thể chạy trên một số máy chủ và cơ sở dữ liệu phụ trợ khác nhau, thì sẽ phải trả giá cho việc đó. Nếu ứng dụng của bạn không yêu cầu sự phức tạp này, hãy bỏ qua các phần bổ sung và quay lại giải pháp đơn giản nhất đáp ứng nhu cầu của bạn (KISS & YAGNI).

Vì vậy, để kết thúc, tôi không nghĩ rằng OOP như một khái niệm ngày càng phức tạp hơn, chúng tôi, những người dùng OOP có quyền lựa chọn sử dụng nó theo những cách khác nhau, và đó là một điều tốt.


Xóa điểm. Tôi biết YAGNI. KISS là gì?
tunmise fasipe

2
@tunmisefasipe, KISS là tên viết tắt của một nguyên tắc thiết kế. Các từ gốc là "Keep It Simple (St ngu)" (ref: en.wikipedia.org/wiki/KISS_principl ) nhưng một cụm từ lịch sự hơn có thể là "Keep It So Simple".
NoChance

3
@tunmisefasipe - KISS = Giữ nó đơn giản, ngu ngốc. Một cụm từ tôi lặp lại với chính mình QUÁ, và QUÁ, và QUÁ, và nó dường như không phải lúc nào cũng chìm vào.
Michael Kohne

@MichaelKohne, tất cả chúng ta đều làm thế! Tôi đoán rằng đó là một nghệ thuật để có thể đơn giản hóa mọi thứ. E = M C C nói rất nhiều trong một hình thức rất súc tích!
NoChance

3

Câu trả lời ngắn : Có, bởi vì bạn đối phó với các vấn đề khó khăn hơn.

Câu trả lời dài (thiên vị mạnh mẽ) : Đối với tôi các mẫu thiết kế thường chỉ ra rằng một số mô hình có vấn đề trong khu vực nhất định. Các mẫu OOP xử lý các vấn đề của OOP (ở cấp độ thấp hơn các mẫu Java xử lý các vấn đề của Java), các mẫu FP xử lý các vấn đề của FP, v.v.

Trong quá trình lập trình bạn có thể có những ưu tiên khác nhau. Bạn có thể muốn có chương trình chính xác, bạn có thể muốn rút ngắn thời gian tiếp thị, chương trình nhanh nhất có thể, khả năng duy trì dài hạn hoặc khả năng duy trì ngay lập tức bằng cách thuê mới. Tùy thuộc vào độ rậm rạp của bạn, bạn sẽ có sự khác biệt lớn - nếu bạn là người điều khiển lập trình của nhà máy điện, bạn muốn thực hiện ngay lần đầu tiên và không phải sửa lỗi mỗi lần sau đó ("Meltdown có xảy ra mỗi khi bạn nhấn Ctrl+Alt+Delkhông?"). Nếu bạn ở trong HPC, logic có thể đơn giản tương đối nhưng bạn muốn thực thi nó nhanh nhất có thể, v.v. Ngoài ra, một số mô hình phù hợp với một số vấn đề nhất định hơn (ví dụ như lập trình AI và logic, dữ liệu và cơ sở dữ liệu quan hệ).

OOP là một số mở rộng 'quá tốt' trong các trường hợp đơn giản và đó là câu chuyện "mô hình hóa cuộc sống thực". Ví dụ trong cuốn sách đầu tiên về OOP tôi đọc đã có các lớp học Person, EmployeeManagervới is-amối quan hệ. Cho đến nay rất tốt nhưng nếu nhân viên được thăng chức lên quản lý thì sao?

Mặt khác, các mô hình khác có những bài học lần đầu khó hơn - ví dụ như FP với các biến số bất biến (điều buồn cười là những người có kinh nghiệm lập trình thường khó học hơn những người mà đây là ngôn ngữ đầu tiên) - tuy nhiên cuối cùng họ là không khó hơn OOP. Kiểm tra các hàm thuần túy là chuyện nhỏ và trong Haskell / Scala / ... bạn có các công cụ tạo các bài kiểm tra cho mình.

Tái bút Có - câu trả lời thiên vị so với OOP và tôi thừa nhận rằng với một số người mở rộng thì đó là 'phản ứng' với OOP. OOP có công dụng của nó nhưng nó không phải là giải pháp tối ưu duy nhất theo quan điểm của tôi.

PPS. Có - sử dụng các mẫu thiết kế - chúng làm cho việc lập trình OOP đơn giản hơn.

PPPS. Tôi đã sử dụng OOP như từ đồng nghĩa của lập trình mệnh lệnh OOP.


2

Tôi nghĩ đó là một trường hợp của các tài liệu và ví dụ trở nên thực tế hơn.

Các sách OOP ban đầu (đặc biệt là các sách Java sớm) đã trình bày một quan điểm đơn giản hóa vô lý về lập trình ứng dụng. Các ví dụ "Ghi nợ tài khoản ngân hàng với chương trình Java 10 dòng" luôn đặc biệt khó chịu vì tôi đã thấy các ví dụ thực tế của tác vụ đơn giản này chạy tới 6000 dòng mã COBOL (và nỗ lực thay thế Java chạy tới 3500 dòng trước khi bị bỏ rơi như không khả thi!).

Rất may, các sách OO hiện có xu hướng thừa nhận sự phức tạp của cuộc sống thực và cung cấp các ví dụ hữu ích về cách đối phó với chúng.

Nhưng nếu bạn muốn xem cách chạy tài khoản ngân hàng chỉ trong 15 dòng lập trình chức năng mã là người đàn ông của bạn

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.