How to mark a method obligatory?

后端 未结 6 513
囚心锁ツ
囚心锁ツ 2020-12-30 10:21

Suppose you create a class names Person using the builder pattern, and suppose the Builder class contains methods body(), head(), arms()

相关标签:
6条回答
  • 2020-12-30 10:56

    Here is an example with using different types to make some parts mandatory (it also makes the order you call the methods mandatory):

    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;
        }
    }
    


    Edit

    The OP was so impressed with this answer that he wrote it up fully in a blog. It's such a clever take on the builder pattern that a full treatment deserves to be referenced here.

    0 讨论(0)
  • 2020-12-30 10:56

    isn't possible to call these methods in Person's constructor ?

    0 讨论(0)
  • 2020-12-30 10:57

    Maybe inside of build() you could check if all the required methods have been called. Behaps the Person instance has some internal sanity check which is triggered by build().

    Of course this checks runtime behaviour and is no static analysis as you describe it.

    0 讨论(0)
  • 2020-12-30 11:01

    I believe the correct use of the builder pattern would solve the issue you're having.

    I would create class PersonBuilder which would contain the methods setBody() and setArms() and every other optional parameter setter method. The constructor of the builder would take the required parameters. Then the method build() would return the new instance of 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);
        }
    }
    

    Alternatively you could pass the Head parameter to the method build() but I prefer passing it in the constructor instead.

    0 讨论(0)
  • 2020-12-30 11:02

    Why not calling body(), head(), arms() in the build()-Method if it is really mandatory and returning Person in the build() method?

    [edit]

    Short example:

    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 讨论(0)
  • 2020-12-30 11:19

    No way with the compiler.

    You can do is throw a runtime exception from the build() method that the builder is not properly initialized (and have a test that is invoked in the maven test phase)

    But you can also have build(..) accept a HeadDetails object. That way tou can't invoke build without specifying the obligatory parameters.

    0 讨论(0)
提交回复
热议问题