Tại sao một trình xây dựng nên là một lớp bên trong thay vì trong tệp lớp riêng của nó?


24

Nhiều Builder Patternví dụ làm cho Buildermột lớp bên trong của đối tượng mà nó xây dựng.

Điều này có ý nghĩa vì nó chỉ ra những gì các Builderbản dựng. Tuy nhiên, trong một ngôn ngữ gõ tĩnh, chúng ta biết những gì các Builderbản dựng.

Mặt khác, nếu Builderlà một lớp bên trong, bạn nên biết lớp nào được Builderxây dựng mà không cần nhìn vào bên trong Builder.

Ngoài ra, có trình xây dựng như một lớp bên trong làm giảm số lượng nhập khẩu vì nó có thể được tham chiếu bởi lớp bên ngoài - nếu bạn quan tâm đến điều đó.

Và sau đó, có những ví dụ thực tế trong đó Builderlà trong cùng một gói, nhưng không phải là một lớp bên trong, như thế StringBuilder. Bạn biết rằng Builder nên xây dựng một Stringvì nó được đặt tên như vậy.

Điều đó đang được nói, lý do chính đáng duy nhất tôi có thể nghĩ đến để tạo ra một Builderlớp bên trong là bạn biết lớp đó Builderlà gì mà không biết tên của nó hoặc dựa vào các quy ước đặt tên. Ví dụ, nếu StringBuilderlà một lớp bên trong của Stringtôi có lẽ đã biết nó tồn tại sớm hơn tôi (đầu cơ).

Có bất kỳ lý do nào khác để làm cho Buildermột lớp bên trong hoặc nó chỉ đi xuống theo sở thích và nghi lễ?

Câu trả lời:


30

Tôi nghĩ rằng lý do để làm điều này là để lớp bên trong (Builder) có thể truy cập các thành viên riêng của lớp mà nó đang xây dựng.

Từ http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html

Các lớp lồng nhau không tĩnh (các lớp bên trong) có quyền truy cập vào các thành viên khác của lớp kèm theo, ngay cả khi chúng được khai báo là riêng tư.

...

Hãy xem xét hai lớp cấp cao nhất là A và B, trong đó B cần truy cập vào các thành viên của A mà nếu không sẽ được khai báo là riêng tư. Bằng cách ẩn lớp B trong lớp A, các thành viên của A có thể được khai báo là riêng tư và B có thể truy cập chúng.

...

Như với các phương thức và biến đối tượng, một lớp bên trong được liên kết với một thể hiện của lớp kèm theo của nó và có quyền truy cập trực tiếp vào các phương thức và trường của đối tượng đó.

Đây là một số mã để cố gắng minh họa điều này:

class Example {

    private int x;

    public int getX() { return this.x; }

    public static class Builder {

        public Example Create() {
            Example instance = new Example();
            instance.x = 5; // Builder can access Example's private member variable
            return instance;
        }
    }
}

Là một lớp tĩnh, Builder không có một ví dụ cụ thể về Ví dụ mà nó được gắn với. Tuy nhiên, với một ví dụ của Ví dụ (hoặc một ví dụ mà chính nó tạo ra) Builder vẫn có thể truy cập các thành viên riêng của cá thể đó.


Câu trả lời tuyệt vời, điều đó có ý nghĩa! Tuy nhiên, các mẫu trình xây dựng thường có một lớp bên trong tĩnh và chỉ có thể truy cập các thành viên riêng tĩnh của lớp bên ngoài. Nếu bạn có một trình xây dựng cho một lớp khởi tạo thì đó sẽ là tất cả các loại lạ.
Nathanial

1
@Nathanial hoàn toàn không, các biến cá thể riêng tư cũng có thể truy cập được: ideone.com/7DyjDR
amon

1
@nathanial: Có, nhưng người xây dựng không thao túng lớp; nó đang thao túng một đối tượng của lớp mà chính trình xây dựng đã khởi tạo.
Robert Harvey

@amon Tôi thấy bạn đã làm gì ở đó. Cảm ơn đã giải thích!
Nathanial

Cụ thể, nó cung cấp cho trình xây dựng quyền truy cập vào một hàm tạo riêng cho lớp đang được xây dựng, cho phép lớp đó là bất biến (tất cả các trường cuối cùng) và chỉ có thể thực hiện được thông qua trình xây dựng.
Matthew McPeak

1

Không có "nên" trong trường hợp này. Việc xác định một trình xây dựng bên trong một lớp khác hoặc tách nó là trực giao với mẫu Builder. Nhiều ví dụ thực hiện điều này do sự thuận tiện của việc trình bày mã trong một tệp nhất quán (cũng để truy cập các thành viên tư nhân nhưng điều đó cũng phụ thuộc vào ngữ cảnh). Hãy làm khác đi


Không chắc chắn tại sao câu trả lời này đã bị bỏ phiếu, vì bất kỳ lý do nào khác ngoài "vì đó không phải là cách chúng tôi thực hiện nó trong Java." Mẫu xây dựng cung cấp một trình bao bọc xung quanh một hàm tạo có một loạt các tham số. Nếu hàm tạo lấy các tham số đó, thì không cần đối tượng Builder để truy cập các thành viên riêng.
Greg Burghardt
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.