2012-02-03 9 views
8

Giả sử bạn tạo một tên lớp người sử dụng mô hình xây dựng, và giả sử lớp Builder chứa phương pháp body(), head(), arms() và tất nhiên build() và bạn xem xét phương pháp head()build() bắt buộc cho người sử dụng của lớp này.Làm thế nào để đánh dấu một phương thức bắt buộc?

Chúng tôi muốn bằng cách nào đó đánh dấu các phương pháp này bắt buộc, nếu có thể bằng cách sử dụng chú thích. Nếu người dùng của lớp này cố gắng xây dựng một cá thể Person nhưng quên gọi một trong hai phương thức này, chúng tôi muốn nhận một số cảnh báo - hoặc từ trình biên dịch java, hoặc có thể từ Eclipse hoặc Maven, mà chúng tôi sử dụng để xây dựng dự án - bất kỳ dự án nào cũng sẽ làm.

Có thể thực hiện không? Bạn sẽ đề xuất cách nào?

+0

Nghi ngờ bạn có thể thực hiện việc này vào thời gian biên dịch, ngoại trừ trong trường hợp * rất * đặc biệt. Nên khá dễ dàng để có kiểm tra như thế này tại thời gian chạy mặc dù (tôi làm điều này tất cả các thời gian). – NPE

+1

Tôi không thể tưởng tượng một cách để làm điều này, sau đó thêm các thuộc tính bắt buộc làm đối số cho hàm tạo hoặc tạo một ngoại lệ khi 'build' được gọi, nhưng tôi tò mò nếu ai đó có ý tưởng tốt hơn. –

Trả lời

15

Dưới đây là một ví dụ với việc sử dụng các loại khác nhau để làm cho một số bộ phận bắt buộc (nó cũng làm theo thứ tự bạn gọi các phương pháp bắt buộc):

package test; 

import test.StepOne.StepThree; 
import test.StepOne.StepTwo; 
import test.StepOne.LastStep; 

public class TestBuilder { 

    public static void main(String[] args) { 

     String person1 = PersonBuilder.newInstance().head("head").body("body").arm("arm").leg("leg").build(); 

     String person2 = PersonBuilder.newInstance().head("head").body("body").arm("arm").build(); 

    } 

} 

interface StepOne { 

    // mandatory 
    StepTwo head(String head); 

    interface StepTwo { 
     // mandatory 
     StepThree body(String body); 
    } 

    interface StepThree { 
     // mandatory 
     LastStep arm(String arm); 
    } 

    // all methods in this interface are not mandatory 
    interface LastStep { 
     LastStep leg(String leg); 
     String build(); 
    } 

} 

class PersonBuilder implements StepOne, StepTwo, StepThree, LastStep { 

    String head; 
    String body; 
    String arm; 
    String leg; 

    static StepOne newInstance() { 
     return new PersonBuilder(); 
    } 

    private PersonBuilder() { 
    } 



    public StepTwo head(String head) { 
     this.head = head; 
     return this; 
    } 

    public LastStep arm(String arm) { 
     this.arm = arm; 
     return this; 
    } 

    public StepThree body(String body) { 
     this.body = body; 
     return this; 
    } 

    public LastStep leg(String leg) { 
     this.leg = leg; 
     return this; 
    } 

    public String build() { 
     return head + body + arm + leg; 
    } 
} 


Sửa

Các OP rất ấn tượng với câu trả lời này rằng anh đã viết nó hoàn toàn trong một số blog. Đó là một thông minh như vậy trên mô hình xây dựng mà một điều trị đầy đủ xứng đáng được tham chiếu ở đây.

+0

Đó là một cách tiếp cận rất thú vị! Nhưng nó có thể được thực hiện mà không ép buộc thứ tự, i. e. với các giao diện như Bắt buộc và NonMandatory? – uzilan

+0

Không, bạn phải ép buộc thứ tự bởi vì trong mỗi giao diện bạn cần một phương thức trả về bước tiếp theo, vì vậy ngay sau khi bạn đặt một số phương thức vào một trong các giao diện, bạn sẽ buộc chỉ gọi một trong số chúng để có thể điều hướng đến bước tiếp theo ... – pgras

+0

Nhưng bạn có thể thêm vào các phương thức giao diện không thêm thuộc tính (ví dụ 'PersonBuilder.newInstance(). head (" head "). doesntHaveABody(). arm (" arm ")' – yannick1976

1

Không có cách nào với trình biên dịch.

Bạn có thể làm là ném một ngoại lệ thời gian chạy từ build() phương pháp mà các nhà xây dựng không được khởi tạo đúng cách (và có một bài kiểm tra đó được gọi trong giai đoạn thử nghiệm maven)

Nhưng bạn cũng có thể build(..) chấp nhận một HeadDetails vật. Bằng cách đó, bạn không thể gọi xây dựng mà không chỉ định các tham số bắt buộc.

0

Có thể bên trong số build() bạn có thể kiểm tra xem tất cả các phương pháp bắt buộc đã được gọi hay chưa. Có lẽ ví dụ Person có một số kiểm tra sanity nội bộ được kích hoạt bởi build().

Tất nhiên, thao tác này sẽ kiểm tra hành vi thời gian chạy và không có phân tích tĩnh như bạn mô tả.

0

là không thể gọi các phương pháp này trong constructor Person không?

+1

Một trong những ý tưởng với mẫu trình xây dựng là người dùng có thể chọn phương thức nào trong Trình tạo mà cô ấy muốn gọi. Khác là để tránh các nhà xây dựng với nhiều đối số và nhiều quá tải (bao gồm tất cả các cách có thể để tạo ra đối tượng này). Tôi sợ những gì bạn đề nghị có thể phá vỡ những lợi ích này. Chúng tôi muốn giữ quyền tự do của người dùng để tạo đối tượng Person với bất kỳ phương thức nào họ cần, nhưng đồng thời khẳng định rằng một số phương thức bắt buộc được gọi, tốt nhất là trong thời gian xây dựng. – uzilan

1

cơ thể Tại sao không gọi(), người đứng đầu(), cánh tay() trong xây dựng() - Phương pháp nếu nó thực sự bắt buộc và người trở về trong phương pháp xây dựng()?

[sửa]

ngắn ví dụ:

public class Builder { 

private final String bodyProp; 

private final String headProp; 

private final String armsProp; 

private String hearProps; 

public Builder(String bodyProp, String headProp, String armsProp) { 
    super(); 
    this.bodyProp = bodyProp; // check preconditions here (eg not null) 
    this.headProp = headProp; 
    this.armsProp = armsProp; 
} 

public void addOptionalHair(String hearProps) { 
    this.hearProps = hearProps; 
} 

public Person build() { 
    Person person = new Person(); 

    person.setBody(buildBody()); 
    // ... 

    return person; 
} 



private Body buildBody() { 
    // do something with bodyProp 
    return new Body(); 
} 


public static class Person { 

    public void setBody(Body buildBody) { 
     // ... 
    } 
} 

public static class Body { 
} 
} 
+0

btw. nếu cơ thể, đầu và cánh tay cần một số tham số và chúng cũng là bắt buộc sau đó đặt chúng vào hàm tạo của trình tạo. – ollins

+0

Các phương thức này yêu cầu các đối số mà tôi phải gửi đến phương thức build(). Điều này là chống lại các mô hình xây dựng như tôi hiểu nó. – uzilan

3

Tôi tin rằng việc sử dụng đúng đắn về mô hình xây dựng sẽ giải quyết vấn đề bạn đang gặp phải.

Tôi sẽ tạo lớp PersonBuilder chứa các phương thức setBody()setArms() và mọi phương thức đặt tham số tùy chọn khác. Hàm khởi tạo của trình tạo sẽ lấy các tham số bắt buộc. Sau đó, phương thức build() sẽ trả lại phiên bản mới Person.

public class PersonBuilder 
{ 
    private final Head head; 
    private Body body; 
    private Arms arms; 

    public PersonBuilder(Head head) 
    { 
     this.head = head; 
    } 

    public void setBody(Body body) 
    { 
     this.body = body; 
    } 

    public void setArms(Arms arms) 
    { 
     this.arms = arms; 
    } 

    public Person build() 
    { 
     return new Person(head, body, arms); 
    } 
} 

Hoặc bạn có thể vượt qua các tham số Head với phương pháp build() nhưng tôi thích đi qua nó trong các nhà xây dựng để thay thế.