Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

So we implemented the builder pattern for most of our domain to help in understandability of what actually being passed to a constructor, and for the normal advantages that a builder gives. The one twist was that we exposed the builder through interfaces so we could chain required functions and unrequired functions to make sure that the correct parameters were passed. I was curious if there was an existing pattern like this.

Example below:

public class Foo
{
   private int someThing;
   private int someThing2;
   private DateTime someThing3;

   private Foo(Builder builder)
   {
       this.someThing = builder.someThing;
       this.someThing2 = builder.someThing2;
       this.someThing3 = builder.someThing3;
   }

   public static RequiredSomething getBuilder()
   {
       return new Builder();
   }

   public interface RequiredSomething { public RequiredDateTime withSomething (int value); }
   public interface RequiredDateTime { public OptionalParamters withDateTime (DateTime value); }
   public interface OptionalParamters { 
      public OptionalParamters withSeomthing2 (int value); 
      public Foo Build ();}

   public static class Builder implements RequiredSomething, RequiredDateTime, OptionalParamters 
   {
      private int someThing;
      private int someThing2;
      private DateTime someThing3;

      public RequiredDateTime withSomething (int value) {someThing = value; return this;}
      public OptionalParamters withDateTime (int value) {someThing = value; return this;}
      public OptionalParamters withSeomthing2 (int value) {someThing = value; return this;}
      public Foo build(){return new Foo(this);}
   }
}

Example of how it's called:

   Foo foo = Foo.getBuilder().withSomething(1).withDateTime(DateTime.now()).build();
   Foo foo2 = Foo.getBuilder().withSomething(1).withDateTime(DateTime.now()).withSomething2(3).build();
share|improve this question
    
Yeah. We call it constructor and properties. –  Euphoric Oct 28 '13 at 7:22

1 Answer 1

What you are doing is essentially limiting the available methods via the type system. Java's type system is unfortunately a bit on the weak side, so that you are rather limited in those respects.

When you look at stronger type systems in languages like Haskell, or Scala, you will come across the term type-level programming. In its full form, type-level programming can actually involve computations being made at compile-time. However, a less strict form of it is leveraging the type system in order to make implicit designs explicit, which is more ofter referred to as working with phantom types.

For example, you often have designs that require a user to first call method a, before calling method b of an object. In weaker type systems, you have to tell your users via comments, or design documents. But technically, they could still call b first, so you might have to add a check of some sort, then throw an exception or something. Lots of work, and lots of error potentials - which you obviously recognized already.

Phantom types on the other hand are used to turn these implicit dependencies between method calls into an explicit compiler-checkable dependency by moving the different methods into different types.

Here is a nice example of phantom types in Java, and here's a simple example comparing them in Haskell and Scala. Essentially, what these examples achieve is encoding a state into the type system. The second article, f.ex., constructs rocket objects, which can only be launch()ed, if they have been filled with fuel and O2, i.e. you can call that method only if you have called other methods before it. In contrast to a solution, which simply implements all of these methods in one class, leveraging phantom types allows the compiler to automatically check this.

In turn, this also means, that in an IDE your auto-complete variations will be limited to the ones that make sense. If you have a rocket object which hasn't been fueled yet, your auto-complete will simply not show you a launch() method.

To come back to your example, you can replace the launch() method with the build() method and think about the different possible variants for which a build process is feasible. Then you define your phantom types based on the elements that need to be told to the builder, and find out if there is an order to them, or if there are multiple independent aspects. In the two posts I linked to, you can see an example with just one aspect (plane being in flight, or landed), and with two independent aspects (rocket being filled up with fuel and O2).

This approach is generally feasible for any number of aspects, but as you encode these into the type system, I would not recommended going too far with it. In terms of code quality/readability it relates to methods with a lot of parameters. We found these to be sub-optimal and causing more problems than what they're worth. Similarly, phantom types being encoded in type parameters means that you end up with lots and lots of type parameters at the cost of readability. Notice that this only applies to independent aspects being encoded as phantom types. Once you have dependent ones, they are encoded via the same type parameter.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.