Quản lý các hàm tạo với nhiều tham số trong Java


105

Trong một số dự án của chúng tôi, có một hệ thống phân cấp lớp bổ sung thêm nhiều tham số khi nó đi xuống chuỗi. Ở phía dưới, một số lớp có thể có tới 30 tham số, 28 trong số đó chỉ được truyền vào hàm tạo siêu.

Tôi thừa nhận rằng sử dụng DI tự động thông qua một cái gì đó như Guice sẽ rất tốt, nhưng vì một số lý do kỹ thuật, các dự án cụ thể này bị hạn chế đối với Java.

Quy ước sắp xếp các đối số theo thứ tự bảng chữ cái theo kiểu không hoạt động bởi vì nếu một kiểu được cấu trúc lại (Vòng tròn bạn đang chuyển vào cho đối số 2 bây giờ là Hình dạng) thì nó có thể đột nhiên không theo thứ tự.

Câu hỏi này có thể là cụ thể và đầy những lời chỉ trích "Nếu đó là vấn đề của bạn, bạn đang làm sai ở cấp độ thiết kế", nhưng tôi chỉ đang tìm kiếm bất kỳ quan điểm nào.

Câu trả lời:


264

Mẫu thiết kế Builder có thể hữu ích. Hãy xem xét ví dụ sau

public class StudentBuilder
{
    private String _name;
    private int _age = 14;      // this has a default
    private String _motto = ""; // most students don't have one

    public StudentBuilder() { }

    public Student buildStudent()
    {
        return new Student(_name, _age, _motto);
    }

    public StudentBuilder name(String _name)
    {
        this._name = _name;
        return this;
    }

    public StudentBuilder age(int _age)
    {
        this._age = _age;
        return this;
    }

    public StudentBuilder motto(String _motto)
    {
        this._motto = _motto;
        return this;
    }
}

Điều này cho phép chúng tôi viết mã như

Student s1 = new StudentBuilder().name("Eli").buildStudent();
Student s2 = new StudentBuilder()
                 .name("Spicoli")
                 .age(16)
                 .motto("Aloha, Mr Hand")
                 .buildStudent();

Nếu chúng ta bỏ đi một trường bắt buộc (có lẽ là bắt buộc phải có tên) thì chúng ta có thể yêu cầu hàm tạo Student ném một ngoại lệ. Và nó cho phép chúng ta có các đối số mặc định / tùy chọn mà không cần theo dõi bất kỳ loại thứ tự đối số nào, vì bất kỳ thứ tự nào của các lệnh gọi đó sẽ hoạt động tốt như nhau.


10
Tất nhiên với nhập tĩnh, bạn thậm chí không bao giờ phải "nhìn thấy" những "nhà xây dựng" này. Ví dụ: bạn có thể có tên các phương thức tĩnh (Tên chuỗi) trả về một trình tạo và Sinh viên (StudentBuilder) trả về một sinh viên. Do đó Student (name ("Joe"). Age (15) .motto ("Tôi đã ướt mình"));
oxbow_lakes 21/10/08

2
@oxbow_lakes: Trong ví dụ của bạn, lớp nào có tên phương thức tĩnh (Tên chuỗi)?
user443854 16/02/12

Về mặt kỹ thuật, có thể sử dụng lớp Học sinh để xây dựng một học sinh mới. Tôi đã thêm các phương thức bên trong lớp Sinh viên và nó hoạt động tốt. Bằng cách này, tôi không cần phải có một lớp xây dựng khác. Tôi không chắc liệu điều này có được mong muốn hay không. Có lý do gì để sử dụng một lớp (StudentBuilder) khác để xây dựng nó không?
WVrock

1
@WVrock: Nó phụ thuộc vào cách triển khai của bạn. Như tôi đã nói trong câu trả lời của mình, thực hiện điều này với chính lớp học sinh có thể khiến lớp học ở trạng thái khởi tạo một nửa, ví dụ như nếu bạn có một trường bắt buộc chưa được khởi tạo.
Eli Courtwright

@EliCourtwright Tôi đoán đó là về sở thích / thiết kế mã. Thay vì làm cho hàm tạo ném ngoại lệ, tôi đã thực hiện buildStudent()phương thức ném ngoại lệ.
WVrock

24

Bạn có thể đóng gói các tham số liên quan bên trong một đối tượng không?

ví dụ: nếu các tham số như


MyClass(String house, String street, String town, String postcode, String country, int foo, double bar) {
  super(String house, String street, String town, String postcode, String country);
  this.foo = foo;
  this.bar = bar;

thì thay vào đó bạn có thể có:


MyClass(Address homeAddress, int foo, double bar) {
  super(homeAddress);
  this.foo = foo;
  this.bar = bar;
}



8

Chà, sử dụng mẫu trình tạo có thể là một giải pháp.

Nhưng một khi bạn đến 20 đến 30 tham số, tôi sẽ đoán rằng có mối quan hệ cao giữa các tham số. Vì vậy, (như đã đề xuất) gói chúng thành các đối tượng dữ liệu lành mạnh về mặt logic có lẽ hợp lý nhất. Bằng cách này, đối tượng dữ liệu đã có thể kiểm tra tính hợp lệ của các ràng buộc giữa các tham số.

Đối với tất cả các dự án của tôi trước đây, một khi tôi đến mức có quá nhiều tham số (và đó là 8 chứ không phải 28!) Tôi đã có thể làm sạch mã bằng cách tạo một mô hình dữ liệu tốt hơn.


4

Vì bạn bị ràng buộc với Java 1.4, nếu bạn muốn DI thì Spring sẽ là một lựa chọn rất phù hợp. DI chỉ hữu ích ở những nơi mà các tham số của phương thức khởi tạo là các dịch vụ hoặc thứ gì đó không thay đổi trong thời gian chạy.

Nếu bạn có tất cả các hàm tạo khác nhau do bạn muốn có các tùy chọn thay đổi về cách tạo một đối tượng, bạn nên xem xét nghiêm túc việc sử dụng mẫu Builder.


Các tham số chủ yếu là các dịch vụ như bạn đã đề cập, và vì vậy DI là những gì tôi cần. Tôi nghĩ rằng mô hình Builder được đề cập trong một vài câu trả lời khác là chính xác những gì tôi đã hy vọng.
Steve Armstrong

4

Giải pháp tốt nhất là không có quá nhiều tham số trong hàm tạo. Chỉ các tham số thực sự cần thiết trong phương thức khởi tạo, là các tham số cần thiết để khởi tạo đối tượng một cách chính xác. Bạn có thể có các hàm tạo với nhiều tham số, nhưng cũng có một hàm tạo chỉ có các tham số tối thiểu. Các hàm tạo bổ sung gọi hàm tạo đơn giản này và sau đó là các bộ thiết lập để thiết lập các tham số khác. Bằng cách này, bạn có thể tránh được vấn đề dây chuyền với ngày càng nhiều tham số, nhưng cũng có một số hàm tạo tiện lợi.



1

Tái cấu trúc để giảm số lượng tham số và độ sâu của hệ thống phân cấp kế thừa của bạn là khá nhiều tất cả những gì tôi có thể nghĩ đến bởi vì, không có gì thực sự sẽ giúp giữ các tham số 20 thứ thẳng hàng. Bạn sẽ phải thực hiện từng cuộc gọi trong khi xem tài liệu.

Một điều bạn có thể làm là nhóm một số tham số được nhóm hợp lý vào đối tượng cấp cao hơn của riêng chúng, nhưng điều đó có vấn đề riêng.

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.