Tại sao tất cả các lớp trong .NET trên toàn cầu kế thừa từ lớp Object?


16

Nó rất thú vị đối với tôi, những lợi thế mang lại cho cách tiếp cận "lớp gốc toàn cầu" cho khung. Nói một cách đơn giản, lý do nào dẫn đến .NET framework được thiết kế để có một lớp đối tượng gốc với chức năng chung phù hợp với tất cả các lớp.

Ngày nay, chúng tôi đang thiết kế khung mới để sử dụng nội bộ (khung theo nền tảng SAP) và tất cả chúng tôi chia thành hai phe - người đầu tiên nghĩ rằng khung đó nên có gốc toàn cầu và thứ hai - người nghĩ ngược lại.

Tôi đang ở trại "gốc toàn cầu". Và lý do của tôi những gì cách tiếp cận như vậy sẽ mang lại sự linh hoạt tốt và giảm chi phí phát triển khiến chúng tôi sẽ không phát triển chức năng chung nữa.

Vì vậy, tôi rất muốn biết lý do nào thực sự thúc đẩy các kiến ​​trúc sư .NET thiết kế khung theo cách đó.


6
Hãy nhớ rằng .NET Framework là một phần của môi trường phát triển phần mềm tổng quát. Các khung cụ thể hơn, như của bạn, có thể không cần đối tượng "root". Có một phần gốc objecttrong .NET framework một phần vì nó cung cấp một số khả năng cơ bản trên tất cả các đối tượng, chẳng hạn như ToString()GetHashCode()
Robert Harvey

10
"Tôi rất thú vị để biết lý do nào thực sự thúc đẩy các kiến ​​trúc sư .NET thiết kế khung theo cách như vậy." Có ba lý do rất chính đáng cho điều đó: 1. Java đã làm theo cách đó, 2. Java đã làm theo cách đó và 3. Java đã làm theo cách đó.
dasblinkenlight

2
@vcsjones: và ví dụ Java đã bị ô nhiễm với wait()/ notify()/ notifyAll()clone().
Joachim Sauer

3
@daskblinkenlight Đó là poo. Java đã không làm theo cách đó.
Dante

2
@dasblinkenlight: FYI, Java hiện đang sao chép C #, với lambdas, các hàm LINQ, v.v ...
Mehrdad

Câu trả lời:


18

Nguyên nhân cấp bách nhất Objectlà các thùng chứa (trước thuốc generic) có thể chứa bất cứ thứ gì thay vì phải đi theo kiểu C "Viết lại cho mọi thứ bạn cần". Tất nhiên, có thể cho rằng, mọi thứ nên được thừa hưởng từ một lớp cụ thể và sau đó lạm dụng thực tế này để mất hoàn toàn mọi đốm an toàn loại là khủng khiếp đến nỗi nó phải là một ánh sáng cảnh báo khổng lồ về việc vận chuyển ngôn ngữ mà không có chung chung, và cũng có nghĩa là đó Objectlà hoàn toàn dư thừa cho mã mới.


6
Đây là câu trả lời đúng. Thiếu sự hỗ trợ chung là lý do duy nhất. Các đối số "phương thức chung" khác không phải là đối số thực vì các phương thức phổ biến không cần phải phổ biến - Ví dụ: 1) ToString: bị lạm dụng trong hầu hết các trường hợp; 2) GetHashCode: tùy thuộc vào chương trình làm gì, hầu hết các lớp không cần phương thức này; 3) GetType: không phải là một phương thức ví dụ
Codism

2
Bằng cách nào thì .NET "hoàn toàn mất đi mọi thứ an toàn kiểu" bằng cách "lạm dụng" ý tưởng rằng mọi thứ nên được kế thừa từ một lớp cụ thể? Có bất kỳ shitcode nào có thể được viết xung quanh Objectmà không thể được viết xung quanh void *trong C ++ không?
Carson63000

3
Ai nói tôi nghĩ void*là tốt hơn? Không phải vậy. Nếu bất cứ điều gì. nó thậm chí còn tồi tệ hơn .
DeadMG

void*là tồi tệ hơn trong C với tất cả các phôi con trỏ ẩn, nhưng C ++ nghiêm ngặt hơn về vấn đề này. Ít nhất bạn phải đúc một cách rõ ràng.
Tamás Szelei

2
@fish: Một thuật ngữ phân minh: trong C, không có thứ gọi là "diễn viên ngầm". Diễn viên là một toán tử rõ ràng chỉ định chuyển đổi. Bạn có nghĩa là " chuyển đổi con trỏ ngầm ".
Keith Thompson

11

Tôi nhớ Eric Lippert đã từng nói rằng việc kế thừa từ System.Objectlớp học đã cung cấp 'giá trị tốt nhất cho khách hàng'. [sửa: vâng, anh ấy đã nói ở đây ]:

... Họ không cần một loại cơ sở chung. Sự lựa chọn này đã không được thực hiện cần thiết. Nó được tạo ra từ mong muốn cung cấp giá trị tốt nhất cho khách hàng.

Khi thiết kế một hệ thống loại, hoặc bất cứ điều gì khác cho vấn đề đó, đôi khi bạn đạt đến các điểm quyết định - bạn phải quyết định X hoặc không-X ... Lợi ích của việc có một loại cơ sở chung vượt trội hơn chi phí và lợi ích ròng nhờ đó tích lũy lớn hơn lợi ích ròng của việc không có loại cơ sở chung. Vì vậy, chúng tôi chọn để có một loại cơ sở phổ biến.

Đó là một câu trả lời khá mơ hồ. Nếu bạn muốn có một câu trả lời cụ thể hơn, hãy thử hỏi một câu hỏi cụ thể hơn.

Có tất cả mọi thứ xuất phát từ System.Objectlớp học cung cấp độ tin cậy và hữu ích mà tôi đã tôn trọng rất nhiều. Tôi biết rằng tất cả các đối tượng sẽ có một loại ( GetType), rằng chúng sẽ phù hợp với các phương thức hoàn thiện của CLR ( Finalize) và tôi có thể sử dụng GetHashCodechúng khi xử lý các bộ sưu tập.


2
Điều này là thiếu sót. Bạn không cần GetType, bạn chỉ cần mở rộng typeofđể thay thế chức năng của nó. Về phần Finalize, thực tế, nhiều loại hoàn toàn không thể hoàn thiện được và không sở hữu một phương thức Finalize có ý nghĩa. Ngoài ra, nhiều loại không thể băm cũng không thể chuyển đổi thành chuỗi - đặc biệt là các loại nội bộ không bao giờ dành cho điều đó và không bao giờ được đưa ra để sử dụng công cộng. Tất cả các loại này có giao diện của chúng bị ô nhiễm không cần thiết.
DeadMG

5
Không, nó không bị biến dị - Tôi chưa bao giờ tuyên bố rằng bạn sẽ sử dụng GetType, Finalizehoặc GetHashCodecho mỗi System.Object. Tôi chỉ tuyên bố rằng họ ở đó nếu bạn muốn họ. Đối với "giao diện của họ không bị ô nhiễm", tôi sẽ đề cập đến câu nói ban đầu của tôi về elippert: "giá trị tốt nhất cho khách hàng". Rõ ràng nhóm .NET đã sẵn sàng đối phó với sự đánh đổi.
gws2

Nếu không cần thiết, thì ô nhiễm giao diện. "Nếu bạn muốn" không bao giờ là một lý do tốt để bao gồm một phương pháp. Nó chỉ nên ở đó bởi vì bạn cần nó và người tiêu dùng của bạn sẽ gọi nó . Khác, nó không tốt Ngoài ra, trích dẫn Lippert của bạn là một lời kêu gọi ngụy biện uy quyền, vì anh ta cũng không nói gì khác ngoài "Điều đó tốt".
DeadMG

Tôi không cố gắng tranh luận quan điểm của bạn @DeadMG - câu hỏi cụ thể là "Tại sao tất cả các lớp trong .NET được thừa hưởng toàn cầu từ lớp Object" và do đó tôi đã liên kết với một bài đăng trước đó bởi một người rất thân với nhóm .NET tại Microsoft, người đã đưa ra một câu trả lời hợp pháp - mặc dù mơ hồ - về lý do tại sao nhóm phát triển .NET chọn phương pháp này.
gws2

Quá mơ hồ để là một câu trả lời cho câu hỏi này.
DeadMG

4

Tôi nghĩ rằng các nhà thiết kế Java và C # đã thêm một đối tượng gốc vì về cơ bản nó là miễn phí đối với họ, như trong bữa trưa miễn phí .

Chi phí thêm một đối tượng gốc rất nhiều bằng chi phí thêm chức năng ảo đầu tiên của bạn. Vì cả CLR và JVM đều là các môi trường được thu gom rác với các bộ hoàn thiện đối tượng, bạn cần có ít nhất một ảo cho phương thức của bạn java.lang.Object.finalizehoặc cho System.Object.Finalizephương thức của bạn . Do đó, chi phí thêm đối tượng gốc của bạn đã được trả trước, bạn có thể nhận được tất cả các lợi ích mà không phải trả tiền cho nó. Đây là điều tốt nhất của cả hai thế giới: những người dùng cần một lớp gốc chung sẽ có được thứ họ muốn và những người dùng không quan tâm sẽ có thể lập trình như thể nó không có ở đó.


4

Dường như với tôi bạn có ba câu hỏi ở đây: một là tại sao một gốc chung được giới thiệu cho .NET, thứ hai là những lợi thế và bất lợi của điều đó, và thứ ba là liệu một yếu tố khung có nên có một toàn cầu hay không nguồn gốc.

Tại sao .NET có một root chung?

Theo nghĩa kỹ thuật nhất, có một gốc chung là điều cần thiết cho sự phản chiếu và cho các thùng chứa tiền thế hệ.

Ngoài ra, theo hiểu biết của tôi, có một gốc chung với các phương thức cơ bản như equals()hashCode()được nhận rất tích cực trong Java và C # bị ảnh hưởng bởi (trong số những người khác) Java, vì vậy họ cũng muốn có tính năng đó.

Những lợi thế và bất lợi của việc có một gốc chung trong một ngôn ngữ là gì?

Ưu điểm của việc có một gốc chung:

  • Bạn có thể cho phép tất cả các đối tượng có một chức năng nhất định mà bạn cho là quan trọng, chẳng hạn như equals()hashCode(). Điều đó có nghĩa là, ví dụ, mọi đối tượng trong Java hoặc C # đều có thể được sử dụng trong bản đồ băm - so sánh tình huống đó với C ++.
  • Bạn có thể tham khảo các đối tượng thuộc loại không xác định - ví dụ: nếu bạn chỉ chuyển thông tin xung quanh, như các thùng chứa tiền chung đã làm.
  • Bạn có thể tham khảo các đối tượng thuộc loại không thể biết - ví dụ: khi sử dụng sự phản chiếu.
  • Nó có thể được sử dụng trong các trường hợp hiếm hoi khi bạn muốn có thể chấp nhận một đối tượng có thể thuộc các loại khác nhau và không liên quan - ví dụ như là một tham số của printfphương thức giống như.
  • Nó cho phép bạn linh hoạt thay đổi hành vi của tất cả các đối tượng bằng cách thay đổi chỉ một lớp. Ví dụ: nếu bạn muốn thêm một phương thức cho tất cả các đối tượng trong chương trình C # của mình, bạn có thể thêm một phương thức mở rộng vào object. Không phổ biến lắm, có lẽ, nhưng không có một gốc chung thì điều đó là không thể.

Nhược điểm của việc có một gốc chung:

  • Nó có thể bị lạm dụng để chỉ một đối tượng có giá trị nào đó ngay cả khi bạn có thể đã sử dụng một loại chính xác hơn cho nó.

Bạn có nên đi với một gốc chung trong dự án khung của bạn?

Rất chủ quan, tất nhiên, nhưng khi tôi nhìn vào danh sách ủng hộ ở trên, tôi chắc chắn sẽ trả lời là . Cụ thể, viên đạn cuối cùng trong danh sách pro - tính linh hoạt của việc thay đổi hành vi của tất cả các đối tượng bằng cách thay đổi root - trở nên rất hữu ích trong một nền tảng, trong đó các thay đổi đối với root có nhiều khả năng được khách hàng chấp nhận hơn là thay đổi toàn bộ ngôn ngữ.

Bên cạnh đó - mặc dù điều này thậm chí còn chủ quan hơn - tôi thấy khái niệm về một gốc chung rất thanh lịch và hấp dẫn. Nó cũng làm cho việc sử dụng công cụ trở nên dễ dàng hơn, ví dụ, giờ đây thật dễ dàng để yêu cầu một công cụ hiển thị tất cả các hậu duệ của gốc chung đó và nhận được một cái nhìn tổng quan, nhanh chóng về các loại khung.

Tất nhiên, các loại phải có ít nhất một chút liên quan đến điều đó, và đặc biệt, tôi không bao giờ hy sinh quy tắc "is-a" chỉ để có một gốc chung.


Tôi nghĩ rằng c # không chỉ bị ảnh hưởng bởi Java, tại một số điểm - Java. Microsoft không thể sử dụng Java nữa nên sẽ mất hàng tỷ đồng đầu tư. Họ bắt đầu với việc đưa ra ngôn ngữ mà họ đã có một tên mới.
Mike Braun

3

Về mặt toán học, sẽ thanh lịch hơn một chút khi có một hệ thống loại chứa hàng đầu và cho phép bạn xác định ngôn ngữ hoàn toàn hơn một chút.

Nếu bạn đang tạo một khung công tác, thì mọi thứ nhất thiết sẽ được sử dụng bởi một cơ sở mã hiện có. Bạn không thể có một siêu kiểu phổ quát vì tất cả các loại khác trong bất kỳ tiêu thụ nào của khung tồn tại.

Tại đó điểm, quyết định để có một lớp cơ sở chung phụ thuộc vào những gì bạn đang làm. Rất hiếm khi nhiều thứ có một hành vi chung rất hữu ích khi tham chiếu những điều này thông qua hành vi chung.

Nhưng nó xảy ra. Nếu có, sau đó đi thẳng vào trừu tượng hóa hành vi phổ biến đó.


2

Việc thúc đẩy một đối tượng gốc vì họ muốn tất cả các lớp trong khung hỗ trợ một số thứ nhất định (lấy mã băm, chuyển đổi thành chuỗi, kiểm tra đẳng thức, v.v.). Cả C # và Java đều thấy hữu ích khi đặt tất cả các tính năng phổ biến này của một Đối tượng trong một số lớp gốc.

Hãy nhớ rằng họ không vi phạm bất kỳ nguyên tắc OOP hay bất cứ điều gì. Bất cứ điều gì trong lớp Object đều có ý nghĩa trong bất kỳ lớp con nào (đọc: bất kỳ lớp nào ) trong hệ thống. Nếu bạn chọn áp dụng thiết kế này, hãy chắc chắn rằng bạn làm theo mẫu này. Đó là, không bao gồm những thứ trong thư mục gốc không thuộc về mọi lớp đơn lẻ trong hệ thống của bạn. Nếu bạn tuân theo quy tắc này một cách cẩn thận, tôi sẽ không thấy bất kỳ lý do nào khiến bạn không nên có một lớp gốc chứa mã chung, hữu ích cho toàn hệ thống.


2
Điều đó không đúng chút nào. Có nhiều lớp chỉ nội bộ không bao giờ được băm, không bao giờ được phản ánh, không bao giờ được chuyển đổi thành chuỗi. Thừa kế không cần thiết và phương pháp không cần thiết chắc chắn nhất không vi phạm nhiều nguyên tắc.
DeadMG

2

Một vài lý do, chức năng chung tất cả các lớp con có thể chia sẻ. Và nó cũng cung cấp cho các nhà văn khung khả năng viết rất nhiều chức năng khác vào khung mọi thứ có thể sử dụng. Một ví dụ sẽ là bộ nhớ đệm ASP.NET và các phiên. Hầu như mọi thứ đều có thể được lưu trữ trong chúng, bởi vì chúng đã viết các phương thức add để chấp nhận các đối tượng.

Một lớp gốc có thể rất lôi cuốn, nhưng nó rất, rất dễ sử dụng sai. Thay vào đó có thể có một giao diện gốc? Và chỉ có một hoặc hai phương pháp nhỏ? Hoặc điều đó sẽ thêm nhiều mã hơn mức cần thiết cho khung của bạn?

Tôi hỏi tôi tò mò về chức năng bạn cần để hiển thị cho tất cả các lớp có thể trong khung bạn đang viết. Điều đó sẽ thực sự được sử dụng bởi tất cả các đối tượng? Hoặc bởi hầu hết trong số họ? Và một khi bạn tạo lớp gốc, làm thế nào bạn sẽ ngăn mọi người thêm chức năng ngẫu nhiên vào nó? Hoặc các biến ngẫu nhiên mà họ muốn là "toàn cầu"?

Vài năm trước có một ứng dụng rất lớn nơi tôi đã tạo một lớp gốc. Sau một vài tháng phát triển, nó đã được tạo ra bởi mã không có doanh nghiệp ở đó. Chúng tôi đã chuyển đổi một ứng dụng ASP cũ và lớp gốc là sự thay thế cho tệp global.inc cũ mà chúng tôi đã sử dụng trong quá khứ. Phải học bài học đó một cách khó khăn.


2

Tất cả các đối tượng heap độc lập thừa kế từ Object; điều đó có ý nghĩa bởi vì tất cả các đối tượng heap độc lập phải có các khía cạnh chung nhất định, chẳng hạn như một phương tiện để xác định loại của chúng. Mặt khác, nếu trình thu gom rác có tham chiếu đến một đối tượng heap không xác định, thì sẽ không có cách nào để biết các bit nào trong blob của bộ nhớ được liên kết với đối tượng đó nên được coi là tham chiếu đến các đối tượng heap khác.

Hơn nữa, trong hệ thống kiểu, thuận tiện khi sử dụng cùng một cơ chế để xác định các thành viên của cấu trúc và các thành viên của các lớp. Hành vi của các vị trí lưu trữ loại giá trị (biến, tham số, trường, vị trí mảng, v.v.) rất khác so với vị trí lưu trữ loại lớp, nhưng sự khác biệt về hành vi đó đạt được trong trình biên dịch mã nguồn và công cụ thực thi (bao gồm trình biên dịch JIT) thay vì được thể hiện trong hệ thống loại.

Một hậu quả của điều này là việc xác định loại giá trị xác định hiệu quả hai loại - loại vị trí lưu trữ và loại đối tượng heap. Cái trước có thể được chuyển đổi hoàn toàn sang cái sau và cái sau có thể được chuyển đổi thành cái trước thông qua typecast. Cả hai loại chuyển đổi đều hoạt động bằng cách sao chép tất cả các trường công khai và riêng tư từ một thể hiện của loại được đề cập sang loại khác. Ngoài ra, có thể sử dụng các ràng buộc chung để gọi trực tiếp các thành viên giao diện trên một vị trí lưu trữ loại giá trị, mà không tạo bản sao của nó trước.

Tất cả điều này rất quan trọng vì các tham chiếu đến các đối tượng heap kiểu giá trị hoạt động giống như các tham chiếu lớp và không giống như các loại giá trị. Hãy xem xét, ví dụ, mã sau đây:

chuỗi testEnumerator <T> (T it) trong đó T: IEnumerator <string>
{
  var it2 = nó;
  it.MoveNext ();
  it2.MoveNext ();
  trả lại nó. Hiện tại;
}
kiểm tra khoảng trống công cộng ()
{
  var theList = Danh sách mới <chuỗi> ();
  theList.Add ("Fred");
  theList.Add ("George");
  theList.Add ("Percy");
  theList.Add ("Molly");
  theList.Add ("Ron");

  var enum1 = theList.GetEnumerator ();
  Trình duyệt số <chuỗi> enum2 = enum1;

  Debug.Print (testEnumerator (enum1));
  Debug.Print (testEnumerator (enum1));
  Debug.Print (testEnumerator (enum2));
  Debug.Print (testEnumerator (enum2));
}

Nếu testEnumerator()phương thức được truyền vào một vị trí lưu trữ của loại giá trị, itsẽ nhận được một cá thể có các trường công khai và riêng được sao chép từ giá trị được truyền vào. Biến cục bộit2 sẽ chứa một thể hiện khác có các trường được sao chép từ tất cả it. Gọi MoveNextvào it2sẽ không ảnh hưởng it.

Nếu đoạn mã trên được truyền vào một vị trí lưu trữ của loại lớp, thì giá trị được truyền vào it, và it2, tất cả sẽ tham chiếu đến cùng một đối tượng, và do đó gọi MoveNext()bất kỳ trong số chúng sẽ gọi nó một cách hiệu quả trên tất cả chúng.

Lưu ý rằng việc truyền List<String>.Enumeratorđể IEnumerator<String>chuyển nó một cách hiệu quả từ loại giá trị sang loại lớp. Loại đối tượng heap là List<String>.Enumeratornhưng hành vi của nó sẽ rất khác với loại giá trị cùng tên.


+1 vì không đề cập đến ToString ()
JeffO

1
Đây là tất cả về chi tiết thực hiện. Không cần phải phơi bày những thứ này cho người dùng.
DeadMG

@DeadMG: Ý bạn là gì? Hành vi có thể quan sát được của một List<T>.Enumeratorthứ được lưu trữ dưới dạng List<T>.Enumeratorkhác biệt đáng kể so với hành vi của một thứ được lưu trữ trong một IEnumerator<T>, trong đó việc lưu trữ giá trị của loại trước vào vị trí lưu trữ của một trong hai loại sẽ tạo ra một bản sao trạng thái của điều tra viên, trong khi lưu trữ một giá trị của loại sau vào một vị trí lưu trữ cũng thuộc loại thứ hai sẽ không tạo ra một bản sao.
supercat

Có, nhưng Object để làm với thực tế đó.
DeadMG

@DeadMG: Quan điểm của tôi là một thể hiện heap của kiểu System.Int32cũng là một thể hiện của System.Object, nhưng một vị trí lưu trữ của kiểu System.Int32không chứa một System.Objectthể hiện hay tham chiếu đến một thể hiện.
supercat

2

Thiết kế này thực sự có dấu vết trở lại với Smalltalk, mà tôi sẽ xem phần lớn là một nỗ lực theo đuổi định hướng đối tượng với chi phí gần như bất kỳ và tất cả các mối quan tâm khác. Như vậy, theo tôi, nó có xu hướng sử dụng hướng đối tượng, ngay cả khi các kỹ thuật khác có thể (hoặc thậm chí chắc chắn) vượt trội.

Có một hệ thống phân cấp duy nhất với Object(hoặc một cái gì đó tương tự) ở gốc giúp cho việc tạo các lớp bộ sưu tập của bạn thành các bộ sưu tập khá dễ dàng Object, vì vậy, một bộ sưu tập có thể chứa bất kỳ loại đối tượng nào.

Đổi lại cho lợi thế khá nhỏ này, bạn nhận được một loạt các nhược điểm mặc dù. Đầu tiên, từ quan điểm thiết kế, bạn kết thúc với một số ý tưởng thực sự điên rồ. Ít nhất là theo quan điểm của Java về vũ trụ, chủ nghĩa vô thần và một khu rừng có điểm gì chung? Rằng cả hai đều có mã băm! Bản đồ có phải là một bộ sưu tập không? Theo Java, không, không phải vậy!

Vào những năm 70 khi Smalltalk được thiết kế, loại vô nghĩa này đã được chấp nhận, chủ yếu vì không ai thiết kế một giải pháp thay thế hợp lý. Tuy nhiên, Smalltalk đã được hoàn thiện vào năm 1980 và đến năm 1983 Ada (bao gồm cả thuốc generic) đã được thiết kế. Mặc dù Ada chưa bao giờ đạt được mức độ phổ biến như một số dự đoán, nhưng tổng quát của nó đủ để hỗ trợ các bộ sưu tập các đối tượng thuộc loại tùy ý - không có sự điên rồ vốn có trong hệ thống phân cấp nguyên khối.

Khi Java (và ở mức độ thấp hơn, .NET) được thiết kế, hệ thống phân cấp lớp nguyên khối có thể được xem là một lựa chọn "an toàn" - một vấn đề, nhưng chủ yếu là các vấn đề đã biết . Ngược lại, lập trình chung là một chương trình mà hầu hết mọi người (thậm chí sau đó) nhận ra ít nhất về mặt lý thuyết là cách tiếp cận tốt hơn cho vấn đề, nhưng một cách mà nhiều nhà phát triển định hướng thương mại coi là khám phá khá kém và / hoặc rủi ro (ví dụ, trong thế giới thương mại , Ada phần lớn bị coi là một thất bại).

Hãy để tôi rõ ràng mặc dù: hệ thống phân cấp nguyên khối là một sai lầm. Những lý do cho sai lầm đó ít nhất là dễ hiểu, nhưng dù sao đó cũng là một sai lầm. Đây là một thiết kế tồi và các vấn đề thiết kế của nó đã lan truyền gần như tất cả các mã sử dụng nó.

Tuy nhiên, đối với một thiết kế mới ngày nay, không có câu hỏi hợp lý nào: sử dụng hệ thống phân cấp nguyên khối là một sai lầm rõ ràng và một ý tưởng tồi.


Thật đáng để nói rằng các mẫu được biết là tuyệt vời và hữu ích trước khi .NET được xuất xưởng.
DeadMG

Trong thế giới thương mại, Ada một thất bại, không nhiều do tính dài dòng của nó, nhưng do thiếu giao diện được tiêu chuẩn hóa cho các dịch vụ hệ điều hành. Không có API tiêu chuẩn cho hệ thống tệp, đồ họa, mạng, v.v. khiến cho việc phát triển các ứng dụng 'được lưu trữ' của Ada trở nên vô cùng tốn kém.
kevin cline

@kevincline: Có lẽ tôi nên nói một chút khác biệt - về hiệu ứng mà toàn bộ Ada đã bị loại bỏ là một thất bại do sự thất bại của nó trên thị trường. Từ chối sử dụng Ada là (IMO) khá hợp lý - nhưng từ chối học hỏi từ nó ít hơn nhiều (tốt nhất).
Jerry Coffin

@Jerry: Tôi nghĩ rằng các mẫu C ++ đã thông qua các ý tưởng về thuốc generic Ada, sau đó cải thiện chúng rất nhiều bằng cách khởi tạo ngầm.
kevin cline

1

Những gì bạn muốn làm thực sự thú vị, thật khó để chứng minh nếu nó sai hay đúng cho đến khi bạn hoàn thành.

Dưới đây là một số điều cần suy nghĩ:

  • Khi nào bạn sẽ cố tình vượt qua đối tượng cấp cao nhất này trên một đối tượng cụ thể hơn?
  • Mã nào bạn định đưa vào mỗi một lớp của bạn?

Đó là hai điều duy nhất có thể mang lại lợi ích từ một gốc được chia sẻ. Trong một ngôn ngữ, nó được sử dụng để xác định một vài phương thức rất phổ biến và cho phép bạn vượt qua các đối tượng chưa được xác định, nhưng những ngôn ngữ đó không nên áp dụng cho bạn.

Ngoài ra, từ kinh nghiệm cá nhân:

Tôi đã sử dụng một bộ công cụ một lần được viết bởi một nhà phát triển có nền tảng là Smalltalk. Anh ấy đã làm cho nó để tất cả các lớp "Dữ liệu" của anh ấy mở rộng một lớp duy nhất và tất cả các phương thức đều lấy lớp đó - cho đến nay vẫn tốt. Vấn đề là các lớp dữ liệu khác nhau không phải lúc nào cũng có thể hoán đổi cho nhau, vì vậy bây giờ trình soạn thảo và trình biên dịch của tôi không thể giúp tôi BẤT CỨ điều gì để chuyển sang một tình huống nhất định và tôi phải tham khảo tài liệu của anh ấy mà không phải lúc nào cũng giúp. .

Đó là thư viện khó sử dụng nhất mà tôi từng phải đối phó.


0

Bởi vì đó là cách của OOP. Điều quan trọng là phải có một loại (đối tượng) có thể đề cập đến bất cứ điều gì. Một đối số của loại đối tượng có thể chấp nhận bất cứ điều gì. Ngoài ra còn có sự kế thừa, bạn có thể chắc chắn rằng ToString (), GetHashCode (), v.v. có sẵn trên mọi thứ và mọi thứ.

Ngay cả Oracle cũng đã nhận ra tầm quan trọng của việc có một loại cơ sở như vậy và đang lên kế hoạch loại bỏ các nguyên thủy trong Java gần 2017


6
Đó không phải là cách của OOP cũng không quan trọng. Bạn không đưa ra lập luận thực tế nào ngoài "Điều đó tốt".
DeadMG

1
@DeadMG Bạn có thể đọc các đối số qua câu đầu tiên. Người nguyên thủy hành xử khác với các đối tượng, do đó buộc người lập trình phải viết nhiều biến thể của cùng một mã mục đích cho các đối tượng và nguyên thủy.
Dante

2
@DeadMG, ông nói nó có nghĩa là bạn có thể giả định ToString()GetType()sẽ có mặt trên mọi đối tượng. Có lẽ đáng để chỉ ra rằng bạn có thể sử dụng một biến loại objectđể lưu trữ bất kỳ đối tượng .NET nào.
JohnL

Ngoài ra, hoàn toàn có thể viết một loại do người dùng xác định có thể chứa tham chiếu của bất kỳ loại nào. Bạn không cần các tính năng ngôn ngữ đặc biệt để đạt được điều đó.
DeadMG

Bạn chỉ nên có một Đối tượng ở các cấp có chứa mã cụ thể, bạn không bao giờ nên có một đối tượng chỉ để liên kết với biểu đồ của bạn. "Đối tượng" thực sự triển khai một vài phương thức quan trọng và hoạt động như một cách để chuyển một đối tượng vào công cụ trong đó loại chưa được tạo.
Bill K
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.