Có phải sự phát triển Java thường liên quan đến việc phân lớp nhiều hơn C # /. NET không?


34

Gần đây tôi đã bắt đầu xem xét sự phát triển của Android. Điều này đã đưa tôi trở lại thế giới phát triển phần mềm Java. Lần cuối cùng tôi làm việc với Java, tôi sẽ thừa nhận, tôi đã không hiểu OOP nhiều như (tôi nghĩ) bây giờ tôi làm.

Chủ yếu sử dụng C # trong sự nghiệp của mình, tôi nhận thấy một sự khác biệt đáng kinh ngạc về cách kế thừa được sử dụng Java và C #.

Trong C # có vẻ như sự kế thừa có thể tránh được trong hầu hết các tình huống. Nhiệm vụ trong tay thường có thể được thực hiện bằng cách sử dụng các lớp cụ thể của khung .NET .

Trong Java, từ những gì tôi thu thập được từ các mẫu mã, có vẻ như khung công tác Java cung cấp nhiều giao diện hoặc các lớp trừu tượng mà sau đó được nhà phát triển triển khai / mở rộng.

Điều này dường như là một sự khác biệt quá lớn để chỉ sôi sục với phong cách. Lý do đằng sau này là gì? Tôi cảm thấy mình sẽ không viết mã Java sạch cho đến khi tôi hiểu điều này.

Ngoài ra, điều này có giới hạn chỉ với SDK Android hay đây là cách tiếp cận trên toàn Java đối với OOP?

Hoặc đặt theo một cách khác,

Điều gì về thiết kế của hai ngôn ngữ này (dường như khuyến khích) sử dụng thừa kế nhiều hơn hoặc ít hơn so với ngôn ngữ kia?

Nếu các ngôn ngữ đối xử với sự kế thừa giống hệt nhau và giả sử quan sát của tôi là hợp lệ, thì điều đó có nghĩa là điều này có liên quan đến việc thiết kế các khung / thư viện chứ không phải các ngôn ngữ. Động lực của loại thiết kế này là gì?


1
Đúng rồi. Java có quá nhiều giao diện. Tôi rất muốn biết lý do tại sao hành vi nhà phát triển này là phổ biến cho một ngôn ngữ cụ thể. Tôi thấy điều này xảy ra thường xuyên hơn trong các dự án Java hơn bất kỳ dự án nào khác. Phải có một lý do cho điều này và không chỉ là một ý kiến.
Phản ứng

1
@MathewFoscarini chỉ là ý kiến của bạn . Trong các dự án Java mà tôi tham gia, các nhà phát triển đã có xu hướng tránh kế thừa như một bệnh dịch. Không có gì có thẩm quyền ở đây, chỉ có ý kiến của tôi . Muốn thăm dò ý kiến ?
gnat

2
Bạn, hầu như, không bao giờ cần phải lấy một lớp từ lớp khác trong Java. Thay vào đó, bạn có thể thực hiện các giao diện để đạt được tính đa hình và thực hiện các đối tượng tổng hợp và ủy quyền các lệnh gọi phương thức để đạt được chức năng bị xáo trộn.
DwB

1
@ThinkingMedia Nói chung, Java tràn ngập những người quá khích / thuần túy OSS. Nguyên tắc học tập là mối quan tâm hàng đầu. Các nhà phát triển .Net là những người thực dụng quan tâm đến việc hoàn thành công việc. Họ coi trọng mã làm việc hơn mã sạch nhất.
Andy

Câu trả lời:


31

Điều này dường như là một sự khác biệt quá lớn để chỉ sôi sục với phong cách. Lý do đằng sau này là gì?

Hiểu biết của tôi là nó chủ yếu chỉ đơn giản là một quyết định phong cách. Chà, có lẽ không phải phong cách, mà là thành ngữ của ngôn ngữ / môi trường. Các nhà phát triển thư viện tiêu chuẩn Java đã tuân theo một bộ hướng dẫn thiết kế và các nhà phát triển .NET khác (mặc dù họ có khả năng xem cách tiếp cận của Java hoạt động như thế nào).

Có rất ít trong các ngôn ngữ thực tế để khuyến khích hoặc từ bỏ sự kế thừa. Chỉ có hai điều tấn công tôi là có liên quan:

  1. .NET đã giới thiệu thuốc generic sớm hơn trong cuộc đời của họ, trước khi quá nhiều mã không chung chung được triển khai. Sự thay thế là rất nhiều sự kế thừa để gõ những thứ chuyên biệt.

  2. Một thay đổi lớn hơn là các đại biểu được .NET hỗ trợ. Trong Java, bạn bị mắc kẹt với sự kế thừa (ẩn danh) để cung cấp cơ bản nhất cho chức năng biến. Điều này dẫn đến một sự khác biệt tương đối lớn về cách mã được thiết kế để tận dụng lợi thế của các đại biểu hoặc để tránh các cấu trúc thừa kế khó xử cần thiết để làm điều đó trong Java.


3
Tôi nghĩ rằng câu trả lời này cung cấp một lời giải thích rất hợp lý. Đặc biệt là quan điểm về thừa kế ẩn danh thay cho đại biểu. Tôi đã quan sát điều này rất nhiều. Cảm ơn.
MetaFight

3
Đừng quên các loại ẩn danh và cây cú pháp / biểu thức lambda đã được giới thiệu trong .NET 3.5. Và dĩ nhiên, việc gõ động chọn tham gia trong .NET 4. Đây gần như là một ngôn ngữ hỗn hợp, không phải là hướng đối tượng.
Aaronaught

vâng, theo kinh nghiệm của tôi, tôi đã sử dụng cả hai (bao gồm cả các dự án hỗn hợp trong đó cùng một người sử dụng cả hai ngôn ngữ), mọi người có xu hướng thích sử dụng số lượng lớn hơn các lớp nhỏ hơn khi mã hóa Java, một số lượng nhỏ hơn các lớp lớn hơn (theo xu hướng các lớp thần) sử dụng C #. Đã cố tình tạo nguyên mẫu giống nhau bằng cách sử dụng cùng một kiểu trong cả hai, bạn sẽ có một số lớp tương tự (sử dụng các lớp một phần, bạn có thể sẽ có nhiều tệp mã hơn ngay cả khi sử dụng C #).
jwenting

6

Đây là những ngôn ngữ rất khác nhau, đặc biệt là trong lĩnh vực này. Giả sử bạn có một lớp học. Trong trường hợp này, chúng tôi sẽ biến nó thành điều khiển người dùng, giống như hộp văn bản. Gọi nó là UIControl. Bây giờ chúng tôi muốn đặt điều này trong một lớp khác. Trong trường hợp này, vì chúng tôi đang sử dụng UI cho ví dụ của mình, chúng tôi sẽ gọi nó là lớp CleverPanel. Ví dụ CleverPanel của chúng tôi sẽ muốn biết về những điều xảy ra với cá thể UIControl của nó vì nhiều lý do. làm như thế nào?

Trong C #, cách tiếp cận cơ bản là kiểm tra các Sự kiện khác nhau, thiết lập các phương thức sẽ thực thi khi mỗi sự kiện thú vị được kích hoạt. Trong Java, thiếu các sự kiện, giải pháp thông thường là chuyển một đối tượng với các phương thức xử lý "sự kiện" khác nhau sang phương thức UIControl:

boolean  stillNeedIt =  ... ;
uiControl.whenSomethingHappens( new DoSomething()  {
    public void resized( Rectangle r )  { ... }
    public boolean canICloseNow()  { return !stillNeedIt; }
    public void closed()  { ... }
    ...
} );

Cho đến nay, sự khác biệt giữa C # và Java không sâu sắc. Tuy nhiên, chúng tôi có giao diện DoS Something không cần thiết trong C #. Ngoài ra, giao diện này có thể bao gồm rất nhiều phương thức không cần thiết hầu hết thời gian. Trong C #, chúng tôi không xử lý Sự kiện đó. Trong Java, chúng tôi tạo một lớp cung cấp một triển khai null cho tất cả các phương thức giao diện, DoS SomethingAd CHƯƠNG. Bây giờ chúng tôi thay thế DoS Something bằng DoS SomethingAdOG và chúng tôi không cần phải viết bất kỳ phương thức nào để biên dịch sạch. Chúng tôi cuối cùng chỉ ghi đè các phương thức chúng tôi cần để làm cho chương trình hoạt động đúng. Vì vậy, cuối cùng chúng ta cần một giao diện sử dụng tính kế thừa trong Java để khớp với những gì chúng ta đã làm với các sự kiện trong C #.

Đây là một ví dụ, không phải là một cuộc thảo luận toàn diện, nhưng nó đưa ra những điều cơ bản về lý do tại sao có quá nhiều sự kế thừa trong Java trái ngược với C #.

Bây giờ, tại sao Java hoạt động theo cách này? Mềm dẻo. Đối tượng được chuyển đến khi nào đó SomethingHappens có thể đã được chuyển đến CleverPanel từ một nơi khác hoàn toàn. Nó có thể là một cái gì đó mà một số trường hợp của CleverPanel nên chuyển đến các đối tượng giống như UIControl của họ để hỗ trợ một đối tượng CleverWindow ở đâu đó. Hoặc UIControl có thể trao nó cho một trong các thành phần của nó .

Ngoài ra, thay vì bộ điều hợp, có thể có một triển khai DoS Something ở đâu đó có hàng ngàn dòng mã phía sau nó. Chúng ta có thể tạo một ví dụ mới về điều đó và vượt qua nó. Chúng ta có thể cần ghi đè một phương thức. Một mẹo phổ biến trong Java là có một lớp lớn với một phương thức như:

public class BigClass implements DoSomething  {
    ...many long methods...
    protected int getDiameter()  { return 5; }
}

Sau đó, trong CleverlPanel:

uiControl.whenSomethingHappens( new BigClass()  {
    @Override
    public int getDiameter()  { return UIPanel.currentDiameter; }
} );

Nền tảng Java nguồn mở thực hiện rất nhiều điều này, điều này có xu hướng thúc đẩy các lập trình viên làm nhiều hơn - cả hai vì họ làm theo nó như một ví dụ và chỉ đơn giản là để sử dụng nó. Tôi nghĩ rằng thiết kế cơ bản của ngôn ngữ đứng sau thiết kế khung của Sun đằng sau việc lập trình viên Java sử dụng các kỹ thuật khi không sử dụng khung.

Thật dễ dàng để tạo một lớp nhanh chóng trong Java. Lớp, ẩn danh hoặc được đặt tên, chỉ cần được tham chiếu trong một khối mã nhỏ được chôn sâu trong một phương thức. Nó có thể được tạo hoàn toàn mới hoặc bằng cách sửa đổi một chút cho một lớp rất lớn, hiện có. (Và lớp hiện tại có thể là cấp cao nhất trong tệp riêng của nó hoặc được lồng trong một lớp cấp cao nhất hoặc chỉ được xác định trong một khối mã duy nhất). Thể hiện lớp mới có thể có toàn quyền truy cập vào tất cả dữ liệu của đối tượng tạo. Và thể hiện mới có thể được thông qua và sử dụng trên toàn bộ chương trình, đại diện cho đối tượng đã tạo ra nó.

(Bên cạnh đó, lưu ý rằng việc sử dụng kế thừa lớn ở đây - như ở những nơi khác trong Java - chỉ đơn giản là cho mục đích DRY. Nó cho phép các lớp khác nhau sử dụng lại cùng một mã. )

Một lần nữa, đây không phải là một cuộc thảo luận toàn diện; Tôi chỉ đang gãi bề mặt ở đây. Nhưng vâng, có một sự khác biệt đáng ngạc nhiên về cách sử dụng tính kế thừa giữa Java và C #. Về mặt này, chúng là những ngôn ngữ rất khác nhau. Đó không phải là trí tưởng tượng của bạn.


Lưu ý: Bạn có thể tránh phải cung cấp các phương thức không có gì bằng cách mở rộng một lớp trừu tượng chứa đầy các triển khai trống. Bằng cách này, bạn có thể ghi đè có chọn lọc các phương thức làm việc gì đó. Trong khi không xấu xí, nó có nghĩa là một mức độ thừa kế khác.
Peter Lawrey

-2

Hoàn toàn không có sự khác biệt trong cách xử lý kế thừa giữa Java và C #. Khi bạn thực sự sẽ sử dụng tính kế thừa hoặc thành phần chắc chắn là một quyết định thiết kế và không có cách nào là điều mà Java hoặc C # khuyến khích hoặc không khuyến khích. Tôi vui lòng đề nghị đọc bài viết này .

Hy vọng tôi đã giúp!


5
Bạn đang nói về chính các ngôn ngữ, nhưng tôi nghĩ câu hỏi cũng là về các thư viện và cách sử dụng phổ biến.
Svick

3
Nhưng có những điều kỳ quặc trong phần còn lại của ngôn ngữ khuyến khích sự kế thừa thêm trong Java; xem câu trả lời của RalphChapin
Izkata
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.