2011-08-10 28 views
6

Đây là vấn đề thiết kế mà tôi tiếp tục gặp phải, vì vậy tôi nghĩ cuối cùng tôi sẽ đưa nó ra và xem mọi người sẽ tiếp cận nó như thế nào. Vấn đề là như sau:Thiết kế OO: xử lý chung các lớp con giới thiệu các trường mới

Tôi xác định một lớp nhất định mà phần lớn mô tả tất cả các trường hợp đối tượng tôi sẽ sử dụng, cả hành vi và dữ liệu khôn ngoan. Đó là tuyệt vời và hoạt động tốt cho các đối tượng cơ bản. Sau đó, một vài loại khác của đối tượng cây trồng lên mà cần cùng một dữ liệu và hành vi, nhưng ngoài ra muốn có thêm một lĩnh vực ở đây và ở đó, hoặc một cấu trúc dữ liệu bổ sung.

Hãy gọi lớp Something:

public class Something { 
    private int id; 
    private String fieldA; 
    private String fieldB; 
    private List<Data> list; 

    // Then we have getters, setters, and some base methods 
} 

Đôi khi chúng ta sẽ cần phải sử dụng SomethingElseSomethingDifferent. Họ là 90% như Something ở chỗ cùng một dữ liệu và hành vi mô tả họ, tuy nhiên họ từng bổ sung đã trường bổ sung mà cần phải được sử dụng bởi phần còn lại của chương trình:

public class SomethingElse extends Something { 
    private String dataSpecificToSomethingElse; 
    // Then we have getters, setters, and some new-data specific methods 
} 

public class SomethingDifferentextends Something { 
    private List<DifferentData> dataSpecificToSomethingDifferent; 
    // Then we have getters, setters, and some new-data specific methods 
} 

Tôi muốn đưa ra với một cách phù hợp để xử lý Thứ gì đó nhóm đối tượng theo cách OO chung, vì tôi không muốn để phần còn lại của ứng dụng của tôi chi tiết thực hiện cụ thể (vì chúng tôi có thể cần thêm SomethingWacky sau này). Tôi không muốn đối phó với các lớp con trực tiếp như là phá vỡ đa hình, và sẽ có khả năng bao gồm một nhu cầu downcast/làm một chuyển đổi loại - yuck.

Các cách tiếp cận tôi có thể nghĩ ra để giải quyết việc này như sau:

  1. Tạo một lớp cơ sở trừu tượng định nghĩa tất cả các phương pháp để Something gia đình. Trẻ em sau đó chỉ thực hiện các hành vi mà họ quan tâm đến việc cung cấp, để lại một NOP/ghi đè trống cho các phương pháp không quan tâm. Điều này cho phép mọi thứ được xử lý giống nhau, nhưng giới thiệu giao diện bloat.
  2. Di chuyển trách nhiệm đến lớp cơ sở thông qua các phương pháp làm việc chung, theo Tell, Don't Ask. Ví dụ này có thể là những thứ như display(), doWork(), persist(), getStateFromDisplay(), vv Mỗi phân lớp sau đó sẽ xem xét dữ liệu của nó khi ghi đè các phương thức cơ sở này. Tôi đọc một bài báo của Allen Holub gần đây cho rằng một cái gì đó như thế này có thể là một thực hành tốt. Điều này dường như đang di chuyển quá nhiều trách nhiệm cho các mối quan tâm bên ngoài đến lớp.
  3. Tạo một số loại dữ liệu nhóm tất cả dữ liệu/hành vi bổ sung từ các lớp con và tham chiếu đến điều đó trong Điều gì đó. Điều này không cảm thấy rất giống OO.

Tôi đã sử dụng phương pháp 1 trong một dự án trước đó - nhưng trong trường hợp đó, mỗi lớp con chỉ thực hiện/overrode các phương thức mà nó quan tâm. thực hiện tất cả hoặc chỉ một số.

Mỗi phương pháp tiếp cận cảm thấy bẩn thỉu theo một cách và tôi thực sự không thích bất kỳ cách nào. Lựa chọn thay thế của tôi là gì? Có lẽ tôi hoàn toàn lạm dụng quyền thừa kế hoặc tiếp cận điều này một cách sai lầm hoàn toàn. Tôi mở ra bất kỳ đề xuất nào và muốn tận dụng các kỹ thuật OO để đưa ra các thiết kế gọn gàng, tách rời. Tôi thực sự muốn biết cách mọi người giải quyết các vấn đề như thế này, và bất kỳ tài nguyên nào bạn có thể giới thiệu tôi sẽ được đánh giá cao.

Cảm ơn

+0

Re # 2: nếu lớp học của bạn đang bền bỉ, bạn có vi phạm trách nhiệm duy nhất không? Tôi cần biết thêm về ngữ cảnh, nhưng có vẻ như với tôi bạn đang thừa kế thừa kế - nếu bạn thực sự cần phải làm những việc khác với 'SomethingElse', nó có thực sự là một phân lớp không? – David

+0

Nó không bền bỉ. Tôi chỉ đang cố gắng liệt kê các hành vi ví dụ có thể di chuyển các mối quan tâm bên ngoài trong lớp học, và sẽ vi phạm SRP như bạn nói. Các lớp con không thực sự làm gì khác, chúng chỉ có thêm thông tin để chăm sóc .. –

Trả lời

3

Khi cần phải thêm SomethingElse, SomethingDifferent vv cây lên, tôi muốn đặt câu hỏi: Liệu SomethingElse thực sự cần để có thể truy xuất từng phần tất cả dữ liệu và các yếu tố hành vi của Something? Hoặc là việc sử dụng Something được giới hạn trong một vài phương pháp?

Nếu đó là sau này, thường là một ý tưởng tốt để đóng gói hành vi cụ thể của Something thường được sử dụng bởi các lớp khác, và sau đó use composition rather than inheritance.

+0

Cảm ơn bạn đã đề xuất. Tôi cố gắng sử dụng bố cục mà một lớp là một phần hữu ích, ở đây mặc dù các lớp con theo nghĩa đen giống như cơ sở - sự khác biệt duy nhất là dữ liệu bổ sung (các trường) là cần thiết như một phụ cho trẻ em .. –

+0

Thật khó để nói mà không có một ví dụ cụ thể, nhưng nếu 3 lớp là 90% như nhau, thì 90% có thể là một ứng cử viên tốt để tách ra khỏi một lớp khác. – oksayt

1

Câu hỏi rất thú vị và phải thừa nhận rằng tôi cũng gặp phải vấn đề tương tự.

Tất cả các bạn đã nói rằng tất cả đều hợp lệ và ý tưởng về phân lớp thực sự là giải quyết các vấn đề mà bạn vừa mô tả. Sử dụng ABC là một nguyên tắc OO tốt vì vậy tôi đề nghị bạn nên xem xét nó nhiều hơn một chút. Tuy nhiên, về mặt định nghĩa tất cả các phương thức giao diện trong lớp cơ sở - bạn sẽ cần phải đánh giá lại điều đó. Đầu tiên tôi nghĩ bạn nên lùi lại một bước và hỏi câu hỏi OO cơ bản về việc liệu tất cả những hành vi đó có áp dụng đối tượng của loại đó không? Tôi cũng nghĩ rằng dựa trên sự biến động của mô hình miền của bạn, bạn sẽ biết tất cả các hành vi có thể trả trước/ngay bây giờ hoặc nếu không bạn có thể không có vấn đề mà bạn vừa mô tả. Tôi nghĩ bạn có thể sử dụng cách tiếp cận trên để cấu trúc lại cây thừa kế của bạn và kết hợp với mẫu thiết kế Decorator để tách riêng việc triển khai và đưa tính ổn định vào cây thừa kế của bạn và cho phép mở rộng thông qua các lớp trang trí.

+0

Bạn có thể làm rõ ý bạn bằng cách sử dụng ABC là nguyên lý OO tốt không? –

+0

ABC = Lớp cơ sở trừu tượng. Lớp cơ sở nên luôn trừu tượng vì nhiều lý do khác nhau như tách giữa triển khai thực hiện và mô hình, cũng như lớp cơ sở thường là một phần đại diện của mô hình thế giới thực và chúng ta sẽ không cho phép abject được tạo ra cho điều đó. –

0

Bạn có thể có một bộ giao diện mô tả các tình huống sử dụng khác nhau xuất hiện trong ứng dụng của bạn. Các interface segregation principle and the single responsibility principle đến tâm trí. Tôi nghĩ rằng một cách tốt hơn để đạt được việc sử dụng lại mã là giữ cho các lớp của bạn nhỏ và tập trung nhất có thể và sử dụng bố cục hơn là thừa kế để ủy quyền một số triển khai giao diện đó.

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