Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
150 views
in Technique[技术] by (71.8m points)

java - How to improve the builder pattern?

Motivation

Recently I searched for a way to initialize a complex object without passing a lot of parameter to the constructor. I tried it with the builder pattern, but I don't like the fact, that I'm not able to check at compile time if I really set all needed values.

Traditional builder pattern

When I use the builder pattern to create my Complex object, the creation is more "typesafe", because it's easier to see what an argument is used for:

new ComplexBuilder()
        .setFirst( "first" )
        .setSecond( "second" )
        .setThird( "third" )
        ...
        .build();

But now I have the problem, that I can easily miss an important parameter. I can check for it inside the build() method, but that is only at runtime. At compile time there is nothing that warns me, if I missed something.

Enhanced builder pattern

Now my idea was to create a builder, that "reminds" me if I missed a needed parameter. My first try looks like this:

public class Complex {
    private String m_first;
    private String m_second;
    private String m_third;

    private Complex() {}

    public static class ComplexBuilder {
        private Complex m_complex;

        public ComplexBuilder() {
            m_complex = new Complex();
        }

        public Builder2 setFirst( String first ) {
            m_complex.m_first = first;
            return new Builder2();
        }

        public class Builder2 {
            private Builder2() {}
            Builder3 setSecond( String second ) {
                m_complex.m_second = second;
                return new Builder3();
            }
        }

        public class Builder3 {
            private Builder3() {}
            Builder4 setThird( String third ) {
                m_complex.m_third = third;
                return new Builder4();
            }
        }

        public class Builder4 {
            private Builder4() {}
            Complex build() {
                return m_complex;
            }
        }
    }
}

As you can see, each setter of the builder class returns a different internal builder class. Each internal builder class provides exactly one setter method and the last one provides only a build() method.

Now the construction of an object again looks like this:

new ComplexBuilder()
    .setFirst( "first" )
    .setSecond( "second" )
    .setThird( "third" )
    .build();

...but there is no way to forget a needed parameter. The compiler wouldn't accept it.

Optional parameters

If I had optional parameters, I would use the last internal builder class Builder4 to set them like a "traditional" builder does, returning itself.

Questions

  • Is this a well known pattern? Does it have a special name?
  • Do you see any pitfalls?
  • Do you have any ideas to improve the implementation - in the sense of fewer lines of code?
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The traditional builder pattern already handles this: simply take the mandatory parameters in the constructor. Of course, nothing prevents a caller from passing null, but neither does your method.

The big problem I see with your method is that you either have a combinatorical explosion of classes with the number of mandatory parameters, or force the user to set the parameters in one particular sqeuence, which is annoying.

Also, it is a lot of additional work.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...