2012-02-29 37 views
25

Tôi đã thảo luận với đồng nghiệp, người đã nhấn mạnh rằng trong các ngôn ngữ như Java và C# không bao giờ có lý do gì để sử dụng lớp cơ sở Tóm tắt thuần túy không thể có được xung quanh việc thiếu nhiều thừa kế.Sự khác biệt giữa lớp Tóm tắt thuần túy và giao diện

Tôi cảm thấy rằng anh ấy sai về điều này, vì tôi đã luôn nghĩ rằng nếu một thứ là danh từ thì đó là một đối tượng, và nếu nó là động từ thì đó là một giao diện.

Ví dụ: nếu tôi muốn xác định loại Bird, nơi tôi muốn thực thi phương pháp fly mà không triển khai phương pháp đó, thì tôi sẽ tạo một lớp trừu tượng thuần túy.

Nếu tôi muốn xác định loại Flies, tôi sẽ đặt giao diện đó theo phương thức fly.

Bird có thể triển khai Flies.

Tôi có sai không?

EDIT:

Đối số rắn duy nhất tôi có thể cung cấp để hỗ trợ quan điểm của tôi là tại một số điểm trong tương lai thiết kế có thể cần phải thay đổi để chim có thể ăn. Nếu tất cả các loài chim ăn như nhau thì điều này sẽ cần phải được thêm vào Bird, làm cho nó không trừu tượng thuần túy.

Nếu Bird là một giao diện, thay đổi này đơn giản là một cơn ác mộng, vì tôi không biết liệu những thứ kế thừa từ một số lớp cơ sở khác cũng thực hiện giao diện Bird của tôi.

+0

+1 - câu hỏi hay và tôi nghĩ sẽ có nhiều lý do hợp lý được khám phá trong các câu trả lời sắp tới cho việc sử dụng lớp trừu tượng. –

+3

Chỉ cần chọn * phần * của câu hỏi của bạn (do đó không đăng câu trả lời *): Tôi sẽ không nói rằng giao diện luôn là * động từ *. Giao diện được sử dụng một * lot * để cho phép một lớp thể hiện một khuôn mặt với thế giới được mô hình hóa tốt nhất như một danh từ. Chỉ cần nhìn vào một số giao diện trong 'java.util':' Comparator', 'Enumeration',' List', 'Iterator',' Map', ... –

+1

Ý kiến ​​giống như mặt sau, mọi người đều có một và một số thì tốt hơn hơn những người khác.Tôi không tin rằng so sánh OOP với ngữ pháp là chính xác nhưng gần gũi của nó. – Lloyd

Trả lời

6

Ngoài chỉnh sửa đầu tiên của bạn, tức là một số yêu cầu trong tương lai. Một trường hợp sử dụng có thể có thể khai báo một hằng số và khởi tạo nó trong lớp trừu tượng.

import java.util.ArrayList; 
import java.util.List; 


public abstract class AbstractPure implements ISomeInterface { 
    public static final List<String> days = new ArrayList<String>(); 
    static{ 
     days.add("Monday"); 
     days.add("Tuesday"); 
     days.add("Wednesday");  
     days.add("Thursday"); 
     days.add("Friday"); 
     days.add("Saturday"); 
     days.add("Sunday"); 
    } 
} 
+1

Điểm rất tốt! – sji

+6

Về mặt kỹ thuật, đó không phải là lớp trừu tượng thuần túy nữa ... – zmbq

+1

Cá nhân tôi nghĩ rằng hằng số trong giao diện thường là vấn đề thiết kế - ít nhất mọi thứ không thể được xử lý bởi nguyên thủy và enums. Nhưng đó là một điểm hợp lệ mà điều đó là không thể với các giao diện. – Voo

1

Tôi đã thực hiện một số tìm kiếm trên các lớp trừu tượng thuần túy (đã lâu rồi tôi sử dụng C++) và trường hợp sử dụng duy nhất mà tôi có thể tìm được là xác định giao diện trong C++ (không có giao diện).

Vì vậy, tôi sẽ nói nếu bạn có thể sử dụng một lớp trừu tượng thuần túy, bạn cũng có thể đi với một giao diện, như bạn của bạn đã nói.

Tuy nhiên, tôi chưa bao giờ bắt gặp nhu cầu về lớp trừu tượng thuần túy trong C#, vì vậy đây có thể là một vấn đề giả định.

+0

Tôi đến từ một nền C++, có thể ảnh hưởng đến suy nghĩ của tôi về điều này, một lần nữa tôi đã mở rộng câu hỏi để minh họa một nhu cầu tiềm năng cho một lớp cơ sở trừu tượng. – sji

+1

Có, nhưng làm thế nào bạn có thể biết giao diện nào đột nhiên sẽ phải ăn? – zmbq

0

Tôi sẽ nói rằng cả giao diện và lớp đều xác định đối tượng. Như bạn đã nói, động từ đi đến các phương pháp - chúng là đặc tính của những vật thể này. Trong ví dụ bay của bạn, tôi sẽ khai báo một giao diện FlyingCreature và xác định phương thức bay trong đó (do đó bạn có giao diện như ComparableSerializable không SerializeCompare. Bạn có phương thức compareTo). Cũng về ví dụ khác của bạn - chim: nếu bạn không có bất kỳ logic cho chim thì bạn khai báo nó như là giao diện.

Giao diện được sử dụng để khai báo các thuộc tính chung các loại đối tượng khác nhau sẽ có, chúng nhóm chúng theo phân loại. Sau đó, sử dụng thực tế là bạn biết chúng có cùng giao diện, bạn sẽ có thể xử lý chúng theo cùng một cách.

Tôi không thấy bất kỳ lợi ích nào trong lớp trừu tượng thuần túy, như tôi đã nói cả lớp trừu tượng và giao diện khai báo đối tượng.

+0

Tôi đã mở rộng câu hỏi của mình để chỉ ra một nhược điểm tiềm năng của việc tạo ra giao diện cho chim. – sji

10

tôi có thể nghĩ đến ít nhất một lý do chính đáng: Bạn có thể mở rộng lớp trừu tượng sau này, mà không vi phạm tương thích ngược: Giả sử một lớp/giao diện

abstract class/interface Foo { 
    void foo(); 
} 

Nếu chúng ta sử dụng một giao diện bây giờ chúng ta biết chắc chắn rằng không có cách nào để thêm chức năng bổ sung cho Foo. Điều này có thể dẫn đến những thứ như interface Foo2 implements Foo.

Mặt khác, nếu bạn có lớp trừu tượng, bạn có thể dễ dàng thêm phương thức khác vào nó, miễn là bạn cung cấp triển khai cơ sở. Lưu ý rằng Java8 sẽ cho phép các giao diện làm cơ bản giống nhau - điều này sẽ hữu ích cho các nhà văn thư viện muốn cập nhật thư viện của họ để sử dụng lambdas mà không nhất thiết phải phá vỡ khả năng tương thích với hàng triệu dòng mã đã được viết.

+0

Đây là lý do duy nhất tôi có thể nghĩ đến là tốt. Để lấy mặt khác của đối số: Làm thế nào để bạn biết khi nào một cái gì đó sẽ không bao giờ cần chức năng bổ sung được thực hiện? Khi nào thì một cái gì đó chắc chắn là một giao diện? Tôi có nên không bao giờ sử dụng một giao diện cho sợ hãi tôi có thể cần phải thêm một số chức năng để nó xuống dòng? – sji

+0

@sji Cuối cùng, một cuộc gọi phán quyết phụ thuộc vào trường hợp kinh doanh thực tế, vì vậy ngoài việc hiển nhiên tôi không thấy nhiều điều có thể giúp chúng ta ở đó nói chung. Ít nhất trong Java cũng có một thực tế là không có nhiều thừa kế. Với Java8 cho phép các giao diện để thực hiện mặc định các phương thức nên đi một chặng đường dài để làm cho điều này rõ ràng hơn. – Voo

0

Giả sử bạn có một hệ thống plugin đi kèm với nhiều loại plugin, mỗi loại thực hiện một giao diện khác nhau.

Bây giờ, cũng cho phép bạn nói rằng bạn đang sử dụng sự phản chiếu để tìm các lớp plugin này khi chạy.

Vì chúng là giao diện, một plugin có thể là nhiều loại plugin.

Nếu bạn đặt mỗi loại plugin thành lớp trừu tượng thì bạn kiểm soát thứ bậc thừa kế và có thể đảm bảo mỗi plugin là một loại riêng biệt.

Vì vậy, có sự khác biệt giữa các lớp và giao diện trừu tượng thuần túy. Nó không phải là một trong những bạn cần phải sử dụng nhưng không phải là ++, đệ quy, hoặc thậm chí các đối tượng.

0

Tôi đã đọc điều gì đó không lâu trước đây liên quan đến điều này. Về cơ bản nó nói rằng nếu các mục được liên kết với nhau thì sử dụng một lớp trừu tượng. Nếu nó mô tả các thuộc tính của một cái gì đó thì sử dụng một giao diện.

Vì vậy, sử dụng ví dụ của bạn một con chim sẽ là một lớp trừu tượng bởi vì bạn muốn một con đại bàng hoặc một con vẹt để lấy được từ cùng một vị trí.

Nếu bạn chỉ muốn một cái gì đó như "tờ rơi" thì bạn sẽ làm cho giao diện đó vì chim và máy bay và những thứ khác có thể thực hiện giao diện nhưng chỉ có một thuộc tính này mà chúng có điểm chung.

Điều khác cần xem xét là tại một số điểm bạn có thể muốn thực sự đặt một số phương pháp cụ thể cho chim của bạn. Tất cả các loài chim bay theo cùng một cách sau khi tất cả vì vậy bạn có thể muốn các lớp học để in "flap flap flap" bất cứ khi nào một con chim bay. Nếu bạn đang sử dụng một giao diện, bạn cần phải làm điều đó trên mỗi lớp (hoặc sau đó giới thiệu một lớp cơ sở mới) trong khi nếu bạn đã sử dụng một lớp trừu tượng ở nơi đầu tiên, bạn chỉ cần thêm hành vi ở một nơi.

Các vấn đề liên quan