Tái cấu trúc một lớp trừu tượng hiện có và các tham số của nó


8

Tôi có một abstract class Atuyên bố một phương pháp trừu tượng doStuff. Hiện tại có nhiều lớp kế thừa từ Avà thực hiện doStuff.

Các thể hiện của lớp được khởi tạo vào thời gian chạy thông qua AFactorydựa trên đầu vào của người dùng. Ban đầu tất cả các lớp có cùng một tham số (đầu vào của người dùng). Nhưng bây giờ tôi có một tham số bổ sung mà chỉ một lớp mới kế thừa Anhu cầu.

Vì vậy, phá vỡ nó mặc dù logic sau:

  • Lớp trình thông dịch tạo các thể hiện dựa trên đầu vào của người dùng ( AFactorydĩ nhiên là sử dụng ) không biết về tham số phụ này.

    • Cố gắng đẩy nó vào lớp phiên dịch lớp sẽ thực sự khó xử vì sau đó tôi sẽ phải biết khi nào nên chuyển nó đến nhà máy, nơi đánh bại toàn bộ mục đích của việc có một nhà máy ngay từ đầu.
    • Gửi nó một cách mù quáng vào Nhà máy với hy vọng nó có thể làm điều gì đó với nó có vẻ khá xấu xí.
  • Giải pháp hiện tại của tôi: Trong khi đó tôi đã quyết định tái cấu trúc A.doStuff(Param param)thành A.doStuff(AParams params).

    AParamscó thể giữ những gì từng tham số cần thiết và doStuffcó thể bỏ qua sau đó nếu họ không quan tâm đến chúng. Điều này cũng có vẻ hơi khó xử với tôi và nhắc nhở tôi về việc gửi các cấu trúc trong WIN32API có thể chứa nhiều tham số vô dụng xấu xí và tôi không thích nó.

Có cách nào thanh lịch hơn để tiếp cận vấn đề này? Hoặc một số mẫu thiết kế mà tôi đã bỏ qua và giải quyết điều này?

Ghi chú :

  • Chúng tôi đang sử dụng Java 1.7
  • Tên của lớp là ngớ ngẩn để nhấn mạnh vấn đề thiết kế lý thuyết mà họ có tên chỉ định, có ý nghĩa bình thường trong thực tế :)
  • Tôi đã tìm kiếm khá nhiều nhưng nhận ra rằng khá khó để tìm kiếm trên web các vấn đề lý thuyết trừu tượng cụ thể (trái ngược với lý do tại sao lại Xném Exceptionmã này) Tôi đã quyết định hỏi vì vậy tôi xin lỗi nếu đây là một bản sao.

Chỉnh sửa 1 :

  • Làm rõ: Tôi cần truyền một đối số cụ thể của lớp con cho doStuffphương thức.

EDIT 2 :

  • Tôi không hoàn toàn hiểu ý định của Kilian Foth vì vậy tôi đã viết một số mã giả Java để giúp tôi giải thích rõ hơn vấn đề / hiểu giải pháp của bạn. Vì thế:

    Đây là một bộ xương của vấn đề của tôi.

    Đây là một bộ xương của giải pháp của tôi.

    Đây là những gì tôi nghĩ có thể là giải pháp của Kilian Foth, nhưng tôi không chắc.


Bạn có thể làm rõ nếu vấn đề của bạn là bạn cần thêm một đối số cụ thể vào phương thức xuất xưởng của mình cho một lớp con cụ thể hay là bạn cần truyền một đối số cụ thể của lớp con cho doStuffphương thức đó?
Martin Wickman

@MartinWickman Câu trả lời là: Tôi cần truyền một đối số cụ thể của lớp con cho phương thức doStuff. Cảm ơn bạn đã đưa ra điều này, tôi xin lỗi vì đã không đủ rõ ràng, nhưng tôi nghĩ bây giờ nó tốt hơn :). Tôi đã chỉnh sửa câu hỏi của mình ...
Scis

Có vẻ như tôi đã đánh vào thứ gì đó tương tự như Builder trong các giải pháp bạn đã liên kết (đó là những gì tôi đã làm - tôi chưa bao giờ nghe nói về Builder, nhưng tôi chỉ mã hóa thứ gì đó đã làm những gì tôi cần nó làm).
Amy Blankenship

Bạn có thực sự cần phải truyền param cho doStuff hay giá trị param được biết khi bạn xây dựng đối tượng? Ngoài ra, các param không đến từ đâu?
Aaron Kurtzhals

@AaronKurtzhals Như tôi đã viết trong tệp bộ xương "có vấn đề", hiện tại giá trị của param param được biết đến với tên EntryPointgọi mainmà sau đó gọi một số Interpretermà hiện tại không nhận được thông số phụ như là một tham số và nhà máy cũng vậy. Thông số bổ sung đến từ một loại đầu vào người dùng khác không được mô tả bởi UserInput(rất tiếc là tôi không thể thay đổi).
Scis

Câu trả lời:


9

Quan điểm của một nhà máy là che giấu sự thật rằng bạn có thể lấy các đối tượng từ các lớp hơi khác nhau. Do đó, nếu một số đối tượng này cần dữ liệu nhất định và những đối tượng khác thì không ...

  • Hoặc chúng không đủ tương tự để được sản xuất bởi cùng một nhà máy. Sau đó, bạn cần phải có nhiều hơn một nhà máy và đưa ra quyết định sớm hơn bạn đang làm.

  • Hoặc họ đủ tương tự mà khách hàng không phải chăm sóc cái nào họ nhận được. Sau đó, bạn không thể mong đợi khách hàng quan tâm đến việc có nên gửi thêm dữ liệu hay không. Theo sau họ phải luôn được thông qua, nhưng nhà máy đôi khi sẽ bỏ qua chúng mà không làm phiền khách hàng với chi tiết thực hiện đó. Bất cứ điều gì khác sẽ gây gánh nặng cho khách hàng với sự khác biệt mà nhà máy được cho là che giấu.


Vâng họ đủ tương tự :) nhưng tôi không chắc chắn rằng tôi hiểu giải pháp của bạn. Bạn có thể vui lòng xem câu hỏi đã chỉnh sửa (tôi đã cố gắng tạo một bộ xương cho thấy vấn đề và các cách tiếp cận khác nhau) và cho tôi biết cách giải thích của tôi có đúng hay không.
Scis

2

Tôi xử lý việc này bằng cách sử dụng một cái gì đó giống như Builder có chứa nhiều nhà máy khác nhau. Builder được đưa ra các giá trị băm có chứa các nhà máy để tạo ra nhiều loại đối tượng khác nhau và nó sẽ xem xét hàm băm và truy xuất đúng nhà máy dựa trên bất kỳ tiêu chí nào.

Ví dụ: tôi có nhiều loại câu hỏi và tất cả các loại câu hỏi này có thể được thực hiện bằng cách thực hiện IQuestionFactory. Hầu hết các triển khai IQuestionFactory là các lớp con của BaseQuestionFactory và chúng nhận được XML đại diện cho một câu hỏi và phân tích nó theo các quy tắc của câu hỏi, trả về một số lớp con của BaseQuestion.

Một số câu hỏi cần thêm thông tin, chẳng hạn như nếu đó là câu hỏi điền vào biểu mẫu, có thể có một phần của XML có chứa các câu hỏi xác định các trường được sử dụng trong biểu mẫu. Các nhà máy tạo ra những câu hỏi này triển khai IEnhifiedQuestionFactory và nhà xây dựng sẽ kiểm tra Nhà máy mà nó truy xuất từ ​​Câu hỏi trắc nghiệm và kiểm tra xem liệu nó có thực hiện Giao diện này không. Nếu có, nó sẽ chuyển toàn bộ XML của tệp có chứa các câu hỏi bên cạnh XML riêng lẻ đi đến phương thức createQuestion.

Để cho bạn thấy mức độ linh hoạt này có thể nhận được, một số triển khai IQuestionFactory chỉ đơn giản là các trình bao chứa nhiều nhà máy câu hỏi và họ có thể nhìn vào XML đến và sau đó gọi một nhà máy nội bộ và trả lại bất cứ điều gì tạo ra. Chúng tôi sử dụng điều này khi một tệp XML chứa nhiều loại câu hỏi.

Tuy nhiên, có vẻ như bạn cần một cái gì đó giống như cách chúng tôi xây dựng Bài tập (về cơ bản là Bộ điều khiển bao quanh bộ sưu tập Câu hỏi), trong đó băm (Tập thể dục Bản đồ) được thiết lập để trả về nhà máy mặc định hầu hết thời gian, nhưng trong trường hợp nơi mà nó có một Nhà máy cụ thể được đăng ký, nó sẽ trả lại điều đó. Và chúng tôi có một Nhà máy cụ thể sẽ tạo một lớp con Bài tập có một thuộc tính bổ sung và nó có khả năng bổ sung để xem xét XML và tìm thông tin cần thiết để điền vào thuộc tính đó.

Vì vậy, tôi đồng ý với Killian Foth rằng quan điểm của một nhà máy là che giấu các chi tiết triển khai về cách thức xây dựng đối tượng, nhưng không có gì nói rằng bạn không thể kết hợp nhiều Nhà máy theo cách sáng tạo (ví dụ: Nhà máy có chứa các nhà máy khác làm công việc thực tế).


2
  • Cách tiếp cận thông thường trong các trường hợp như thế này (Lệnh mẫu) là truyền các tham số bổ sung trong hàm tạo. Trong trường hợp của bạn, điều đó có nghĩa là thêm otherArgumentvào Btrong quá trình xây dựng.

  • Xoay logic xung quanh có thể mở ra một số tùy chọn. Ví dụ: di chuyển doStuff sang AParams:

    for (String arg : listOfArgs) {
        AParams p = AParams.create(arg, otherArgument));
        for (A a : listOfA) {
            p.doStuff(a); // Let AParams to the lifting depending on type of A
        }
    }
    
  • Ngoài ra, bạn có thể nuốt niềm tự hào của mình và kiểm tra instanceoftrong vòng lặp và đặt otherArgumentthủ công trước khi gọi doStuff.

Nếu điều trên là không thể, thì bạn không có lựa chọn nào khác ngoài việc làm những gì bạn đang làm (mở rộng đối số tham số). Đừng bao quát những thứ này.

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.