3
\$\begingroup\$

I think I just made a very simple way to implement both builder patterns:

Characters in Go4 builder:

  • Director: Pizza.Maker
  • ConcreteBuilder: Pizza.Recipe

I'm also thinking about how to make Builder an abstract interface so one can have more type of recipes (Hot/Sweet/Sour...).

The advantages:

  • The client doesn't have to know the ingredient types used by Pizza, just tune the parameters of a pizza using Bloch builder. (In my example it just coincident that they're both int.)

  • The client doesn't have to be an expert in making a pizza, i.e. he/she doesn't have know the actual order of steps of making a pizza, because these steps are handled by the director using the Go4 builder pattern.

  • But if the client doesn't have an idea for certain steps of making a pizza, he/she can customize it; just @override it.


public class Pizza
{
    final private int baseSize;
    final private int a;
    final private int b;
    final private int c;

    private Pizza(Recipe builder) {
        baseSize = builder.baseSize;
        a = builder.a;
        b = builder.b;
        c = builder.c;
    }

    public static Pizza Maker(Recipe builder) {
        builder.prepare2();
        builder.prepare1();
        builder.prepare3();
        return new Pizza(builder);
    }

    public static class Recipe {
        private int baseSize;
        private int a;
        private int b;
        private int c;
        public Recipe() {
            baseSize = 0;
            a = 0;
            b = 0;
            c = 0;
        }
        public Recipe baseSize(int s) {
            this.baseSize = s;
            return this;
        }
        public Recipe changeA(int a) {
            this.a = a;
            return this;
        }
        public Recipe changeB(int b) {
            this.b = b;
            return this;
        }
        public Recipe changeC(int c) {
            this.c = c;
            return this;
        }
        public void prepare1() {
            System.out.println("Basic preparing 1");
        }
        public void prepare2() {
            System.out.println("Basic preparing 2");
        }
        public void prepare3() {
            System.out.println("Basic preparing 3");
        }
    }
}

public class Main
{
    public static void main() {
        Pizza.Recipe myRecipe = new Pizza.Recipe() {
            @Override
            public void prepare3() {
                System.out.println("Advanced preparing 3");
            }
        };
        myRecipe.baseSize(10);
        myRecipe.changeA(20);
        myRecipe.changeB(15);
        myRecipe.changeC(25);
        Pizza myPizza = Pizza.Maker(myRecipe);
        System.out.println();
        // One line-er
        Pizza onelinePizza = Pizza.Maker(new Pizza.Recipe()
                                                  .baseSize(10)
                                                  .changeA(20)
                                                  .changeC(25));
    }
}

And the printed result:

Basic preparing 2
Basic preparing 1
Advanced preparing 3

Basic preparing 2
Basic preparing 1
Basic preparing 3

The original purpose of making Builder abstract, described in Go4 design patterns book, is that the client can decide the representation of the product later on, e.g. In my example then I would be able to create many types of pizza using new recipes (maybe real pizza, pixelized pizza, and LEGO pizza, etc).

But I don't know how to make Pizza.Recipe abstract while still make everything simple. If this can be done then the client can design he/she's own preparing order, just like he/she is the cook!

\$\endgroup\$
3
\$\begingroup\$

I'm not familiar with the given pattern, but there are still a few things that should be pointed out.

The method Maker in Pizza should not start with an uppercase letter.

The fields in the Recipe constructor are useless, as an int is automatically given the value of 0 if no other value is assigned to it.

public Recipe() {
    baseSize = 0;
    a = 0;
    b = 0;
    c = 0;
}

should be

public Recipe() {}

The class Recipe has the following methods: changeA(), changeB() and changeC(). However, it also has prepare1(), prepare2() and prepare3().

Though it is a wild guess from my part, I assume that prepare1() is related to the field a, prepare2() is related to b and prepare3() is related to c. Why are the methods not named prepareA(), prepareB() and prepareC() instead?

Which brings me to my next point:

Even if you are experimenting with a pattern, you should still take the time to use relevant method and field names.

Sure, you're learning on the moment, but tomorrow (or in the future), will you be able to make sense of the field names you used? Will you be able to remember what you learned if you base yourself on an unclear example?

Some good examples could have been:

  • changeToppings() and prepareToppings()
  • changeSauce() and prepareSauce()
  • changeCrust() and prepareCrust()

etc.

Obviously, I have no knowledge at all regarding cooking, but I am sure that a recipe with the fields baseSize, toppings, sauce and crust is much more descriptive than a recipe with baseSize, a, b and c.


The following is a tip, so take it or leave it.

When I experiment with patterns, I fully immerse myself in the example I create.

In your case, you decided to use pizzas. Commit to it - use fields like toppings, crust, sauce, cheese, etc. and methods like cook, cut, etc. If you're going to call your class Pizza, it has to be feel like a pizza -- and I've never seen a pizza made of a, b and c. If you really have no idea, then you could use toppingA, toppingB and toppingC, as long as it makes sense.

I don't know if this applies to everybody, but to me, I find it easier to learn/remember something new when I use full words rather than non-descriptive characters

e.g.:

The likelihood of remembering

Oh yeah, that's right, the Pizza class had a topping, a crust and a sauce!

vs

Oh yeah, that's right, the Pizza class had an a, a b and a c!"

\$\endgroup\$
  • \$\begingroup\$ You're right, I take it. \$\endgroup\$ – Niing Jun 4 '18 at 2:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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