2008-12-09 35 views
7

Tôi có giao diện A, mà tôi phải cung cấp một số triển khai khác nhau. Tuy nhiên, những triển khai đó chia sẻ một số phương thức trợ giúp, vì vậy Tôi đã chuyển các phương thức đó sang một lớp cơ sở trừu tượng.Điều gì (không) tuyên bố khi triển khai giao diện với lớp trừu tượng?

Interface A { 
    void doX(); 
} 

abstract Class B implements A { 
    protected void commonY() { 
     // ... 
    } 

    @Override 
    public abstract void doX(); 
} 

Class C extends B { 
    @Override 
    public void doX() { 
     // ... 
    } 
} 

Class D extends B { 
    @Override 
    public void doX() { 
     // ... 
    } 
} 

Mã của tôi làm việc như mong đợi, nhưng tôi có một vài câu hỏi:

  • Tôi có nên khai báo trừu tượng Phương pháp DOX() trong Class B? Tại sao không)?

  • Tôi có nên khai báo rõ ràng "triển khai A" trên Class C và D không? Tại sao không)?

Trả lời

8

Tôi nghĩ rằng nó sẽ được tốt hơn để làm điều đó như sau:

Interface A { 
     void doX(); 
} 

abstract Class B { 
     protected void commonY() { 
       // ... 
     } 
} 

Class C extends B implements A{ 

     public void doX() { 
       // ... 
     } 
} 

Class D extends B implements A{ 

     public void doX() { 
       // ... 
     } 
} 

Bạn không nên pha trộn các giao diện (chữ ký của phương pháp) với việc thực hiện.

+0

Lợi ích của giải pháp này là khi lớp X triển khai Z nhưng yêu cầu chức năng của phương thức commonY được giới thiệu, nó có thể chuyên lớp B. –

+0

Điều này phụ thuộc vào cách sử dụng. Nếu B là cơ sở cho nhiều lần triển khai A, thì nó sẽ triển khai A. Giống như AbstractList hoặc AbstractCollection. – Robin

4
  • Tôi có nên khai báo trừu tượng Phương pháp DOX() trong Class B? Tại sao không)?

No. Đây là lớp trừu tượng - xác định giao diện sẽ có nghĩa là tất cả các lớp con sẽ cần triển khai các phương thức đó. Nói cách khác, nó dư thừa.

  • Tôi có nên khai báo rõ ràng "triển khai A" trên Class C và D không? Tại sao không)?

Không, một lần nữa - vì lớp cha của bạn (Lớp cơ sở trừu tượng) triển khai giao diện đó, lớp con cụ thể của bạn sẽ được đảm bảo triển khai giao diện đó.

0

Lớp trừu tượng triển khai giao diện phải triển khai giao diện đó. Cụ thể, nó phải có một phương thức công khai cho mọi phương thức-tên-và-chữ ký được chỉ định trong giao diện đó.

Thừa kế là chuyển tiếp. Bạn không cần phải viết rằng lớp C triển khai thực hiện giao diện A nếu lớp C bắt nguồn từ lớp B thực hiện giao diện A. Tuy nhiên, cũng không có nhiều hại cho nó.

+0

Tôi không nghĩ lớp trừu tượng phải triển khai mọi phương thức trong giao diện. Tôi vừa thử nghiệm điều này và có vẻ như bạn có thể thực hiện một giao diện trong một lớp trừu tượng mà không thực sự khai báo bất kỳ phương thức nào của giao diện. –

+0

Hmm bạn có thể đúng. Tôi đã đi ra khỏi bộ nhớ của tôi về Java và kinh nghiệm hiện tại của tôi trong C#. Trong C#, một lớp trừu tượng thực hiện một giao diện được yêu cầu để thực hiện tất cả các phương thức giao diện (thậm chí chỉ cần đánh dấu chúng là trừu tượng). – yfeldblum

0

tôi sẽ không tuyên bố doX() trong B và không thêm "implements A" trên CD bởi vì bạn nên not repeat yourself.

Tóm tắt doX() trong B không thêm gì vì nó đã được chỉ định bởi "implements A". Điều này cũng đúng với việc thêm "implements A" vào CD.

Việc sử dụng chỉ có thể đối với những điều khoản sẽ là tài liệu hướng dẫn: Nếu bạn muốn làm cho nó rất rõ ràng rằng C (hoặc D) là-một A, sau đó bạn có thể thêm implements, nhưng bạn nên biết rằng nó thực sự doesn không quan trọng với trình biên dịch.

1

Tôi sẽ chỉ ném tùy chọn khác.

Biến lớp B trừu tượng thành lớp AUtil không triển khai A. Chữ ký của phương thức có thể yêu cầu đối số bổ sung của loại A để làm việc.

C và D triển khai A và khởi tạo AUtil trong nội bộ. Điều này cho phép C và D mở rộng các lớp khác.

+0

Đây chắc chắn là cách tôi sẽ làm điều đó. Tôi là một đối thủ mạnh mẽ của việc sử dụng thừa kế vì lợi ích của việc cung cấp các phương pháp. Đó là những phương pháp tiện ích tĩnh dành cho! – jdmichal

1

Tôi đồng ý với JeeBee: hãy xem xét triển khai các phương thức trợ giúp của bạn ở đâu đó ngoài lớp cơ sở trừu tượng.

Nếu phương thức trợ giúp chung của bạn() chỉ tồn tại trong lớp cơ sở trừu tượng B, tất cả các lớp thực hiện Giao diện A sẽ phải mở rộng lớp cơ sở B để tận dụng lợi thế của việc thực hiện commonY(). Nhưng, bạn có thể không muốn bị kéo dài thêm lớp B.

Ngoài ra, nếu bạn muốn thay đổi việc thực hiện commonY() trong tương lai thì sao? Sau đó, bạn sẽ ảnh hưởng đến rất nhiều triển khai của giao diện A. Nhưng nếu bạn không kiểm soát tất cả các triển khai của giao diện A, bạn có thể ảnh hưởng đến chức năng của chúng (theo cách xấu) mà không có ý định.

Sử dụng lớp cơ sở trừu tượng trong trường hợp này có thể đơn giản lấy đi một số tính linh hoạt mà không trả lại cho bạn bất kỳ điều gì.

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