2011-04-24 36 views
5

Tôi đang xem xét việc sử dụng một lớp trừu tượng với tất cả các thành viên trừu tượng thay vì một giao diện để tránh việc thực hiện giao diện mã bảng nồi hơi rõ ràng. Vì vậy, thay vìLý do không sử dụng lớp trừu tượng thay vì giao diện?

type IMyInterface = 
    abstract Name : string 
    abstract Text : string 

type MyClass() = 
    member __.Name = "name" 
    member __.Text = "text" 
    interface IMyInterface with 
     member this.Name = this.Name 
     member this.Text = this.Text 

Tôi muốn có

[<AbstractClass>] 
type MyAbstractClass() = 
    abstract Name : string 
    abstract Text : string 

type MyClass() = 
    inherit MyAbstractClass() 
    override __.Name = "name" 
    override __.Text = "text" 

Bất kỳ lời cảnh cáo hoặc ý nghĩa tôi cần phải nhận thức đây?

+4

Nếu bạn đang đưa ra quyết định giữa giao diện và lớp cơ sở trừu tượng, bạn cũng có thể xem xét sử dụng cả hai. Cung cấp một loại cơ sở trừu tượng mà những người triển khai có thể * chọn * để kế thừa từ đó và có nó thực hiện một giao diện. Sau đó, chấp nhận tham chiếu đến giao diện, thay vì ABC. Điều này sẽ không hoạt động trong mọi tình huống (ví dụ: mã của bạn thực sự cần mã có trong ABC để tồn tại trên mọi triển khai cụ thể và không thể chấp nhận triển khai thay thế), nhưng thường có thể là một ý tưởng hay. –

+1

@Merlyn Morgan-Graham - Đề xuất tuyệt vời! Tôi đang cố gắng tiếp cận này và cho đến nay nó đang làm việc rất tốt, cho tốt nhất của cả hai thế giới. –

Trả lời

8

Chỉ điều bạn nên biết và đưa ra quyết định có ý thức là một lớp có thể kế thừa từ chỉ một lớp nhưng thực hiện nhiều giao diện.


Bên cạnh đó, một số kiến ​​nghị về việc sử dụng các lớp trừu tượng hay giao diện:

  • Nếu bạn dự đoán tạo ra nhiều phiên bản của thành phần của bạn, tạo ra một lớp trừu tượng . Lớp học trừu tượng cung cấp cách đơn giản và dễ dàng để phiên bản thành phần của bạn. Bằng cách cập nhật lớp cơ sở, tất cả các lớp kế thừa sẽ tự động được cập nhật với thay đổi . Mặt khác, giao diện, không thể thay đổi sau khi được tạo. Nếu cần có phiên bản giao diện mới là , bạn phải tạo giao diện hoàn toàn mới .
  • Nếu chức năng bạn đang tạo sẽ hữu ích trên một phạm vi rộng các đối tượng khác nhau, hãy sử dụng giao diện . Các lớp trừu tượng phải là được sử dụng chủ yếu cho các đối tượng là liên quan chặt chẽ, trong khi giao diện phù hợp nhất để cung cấp chức năng phổ biến cho các lớp không liên quan.
  • Nếu bạn đang thiết kế các bit nhỏ, ngắn gọn về chức năng, hãy sử dụng các giao diện . Nếu bạn đang thiết kế các đơn vị chức năng lớn , hãy sử dụng lớp trừu tượng .
  • Nếu bạn muốn cung cấp chức năng phổ biến, được triển khai trong số tất cả các triển khai của thành phần của bạn, hãy sử dụng một lớp trừu tượng. Các lớp trừu tượng cho phép bạn triển khai một phần lớp học của mình, trong khi các giao diện không chứa thực hiện cho bất kỳ thành viên nào.

http://msdn.microsoft.com/en-us/library/scsyfw1d%28vs.71%29.aspx

Cá nhân, tôi cảm thấy các đề xuất này là chỗ trên. Đặc biệt, Giao diện, mặt khác, không thể thay đổi khi được tạo. Nếu cần một phiên bản giao diện mới, bạn phải tạo một giao diện hoàn toàn mới. là một điểm rất quan trọng.

+0

Phải, cảm ơn - điều đó cũng xuất hiện trong đầu tôi. Chắc chắn là một biggy. –

+1

Không có lý do kỹ thuật nào mà không thể thay đổi giao diện, trừ khi nó được hiển thị qua COM. Khung .Net/ngôn ngữ cho phép bạn. Đối với phiên bản, nó được coi là thực hành không tốt để thực hiện các thay đổi đột phá trên giao diện thư viện công cộng, trừ khi có lý do thực sự tốt, nhưng đề xuất tương tự sẽ áp dụng cho các loại cơ sở trừu tượng, tức là thêm thành viên trừu tượng bổ sung. –

+0

Bạn có thể giải thích ý nghĩa của bạn bằng "khung .Net/ngôn ngữ cho phép bạn" – manojlds

4

Stephen,

Chỉ một, cơ bản nhất và hiển nhiên ... Giao diện cho phép triển khai thay thế; nếu "loại biết rõ được công bố" là một lớp trừu tượng thì sau này bạn không thể cung cấp bất kỳ lựa chọn thay thế nào khác ...Vì vậy, nhược điểm là bạn đang hạn chế các lựa chọn tương lai của bạn; upside là (tùy thuộc vào bao nhiêu người thừa kế có) bạn có thể tiết kiệm rất nhiều mã tấm nồi hơi.

Nếu bạn thực sự thực sự chắc chắn không có triển khai hợp lệ nào khác thì hãy chuyển sang lớp trừu tượng. Nếu không thì hãy dính vào giao diện.

Và tôi cho rằng bạn CÓ THỂ làm cả hai ... và tôi đoán điều đó sẽ mang lại cho bạn nhiều nhất của cả hai thế giới.

Chúc mừng. Keith.

PS: manojlds là đúng, tất nhiên ... và nhiều hơn nữa soooo sucinct ;-)

+0

Tôi nghĩ rằng việc sử dụng giao diện giới hạn các tùy chọn trong tương lai nhiều hơn các lớp trừu tượng. Nếu bạn gửi một giao diện, sau đó bạn không thể thay đổi nó nếu yêu cầu của bạn thay đổi, bởi vì bất kỳ thay đổi nào là thay đổi đột ngột. Các lớp trừu tượng linh hoạt hơn nhiều, vì bạn có thể thêm các thành viên ảo và điều chỉnh việc triển khai bên trong, miễn là các phương thức trừu tượng công khai không thay đổi chữ ký của chúng. –

+0

Đánh dấu, Bạn có một điểm "hợp lệ", nó chỉ là không, IMHO, một "rất quan trọng" một. Theo kinh nghiệm của tôi, nó phổ biến hơn khi cần "một biến thể của một lớp học hiện có"; câu "cần thêm phương thức vào giao diện PUBLISHED hiện có". Khá đơn giản; một khi một giao diện đạt đến giai đoạn xuất bản nó được đặt trong đá; nếu không bạn sẽ không xuất bản nó, bây giờ bạn sẽ? – corlettk

+0

Yêu cầu có thể thay đổi sau khi xuất bản, nhiều hơn bất kỳ ai muốn. Hãy xem xét nếu bạn tiếp xúc với một giao diện plugin và sau đó tìm ra bạn cần nó để làm nhiều hơn nó đã làm.Giải pháp khi sử dụng giao diện là bạn cần tạo giao diện mới và sau đó bạn bị mắc kẹt với việc bảo trì nhiều kiến ​​trúc plugin, nơi có lớp trừu tượng, vấn đề đó không tồn tại, vì các tính năng mới có thể được thêm vào dưới dạng ảo phương pháp. Tôi đã có vấn đề này nhiều lần. Tôi cũng đã thấy điều này nhiều lần trong các dự án mã nguồn mở khác nhau. Mặc dù vậy, tôi không thể nghĩ ra bất kỳ thứ gì trên đầu mình. –

2

Trong lớp trừu tượng, bạn có thể thực hiện một số hành vi phổ biến của tất cả các tầng lớp phụ.

Trong thiết kế giao diện, bạn có thể muốn có phương thức gọi phương thức khác để thực hiện một số tác vụ phức hợp. Ví dụ: predictAll(Instance array) có thể sử dụng predictSingle(Instance) và cung cấp triển khai mặc định cho tất cả các lớp con. Nếu bạn sử dụng giao diện, bạn cần triển khai predictAll trong tất cả các lớp con.

Nhưng điểm này không phải là một vấn đề lớn như đa thừa kế. Tôi thích giao diện hơn lớp trừu tượng.

Giao diện cũng giữ được thiết kế của bạn.

Một điểm nữa: Giao diện khuyến khích thêm chức năng mã hơn lớp trừu tượng. Typeclass trong Haskell là một giao diện mạnh mẽ hơn.

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