Search code examples
javadesign-patternsfactorybuilder

Builder vs Factory Design Pattern in specific code


I would like to ask what is better to use, factory or builder design pattern, in my case.

Long story short, I have class Action with parameters: transferRate, recoverRate, cost and name.

In my program, I will have array with 30 (always same) Action objects. Every has always same setup of parameters.

I am thinking more about using factory but if you give me advice which is better, I would appreciate that.

Short example:

import lombok.Getter;

Factory:

@Getter
abstract public class Action {
    protected double transferRateBlock;
    protected double recoverRateBlock;
    protected int cost;
    protected String name;
}

public class CloseAirports extends Action {
    public CloseAirports(){
        this.transferRateBlock = -0.4;
        this.recoverRateBlock = 0;
        this.cost = 3;
        this.name = "Close airports";
    }
}

public class CloseBorders extends Action {
    public CloseBorders(){
        this.transferRateBlock = -0.5;
        this.recoverRateBlock = 0;
        this.cost = 4;
        this.name = "Close Borders";
    }
}

I have 30 subclasses like that. Every subclass is going to array in another class. Client is just using these actions, never create any. Every is always precreatted.

CloseAirports closeAirports = new CloseAirports();
CloseBorders closeBorders = new CloseBorders();
Action[] allActions = {closeAirports, closeBorders};

Or should i use rather Builder Design Pattern with this implementation ? :

Action closeSchool = new Action().withTransferRateBlock(0.5).withRecoverRateBlock(0).withCost(2).withName("Close Schools");
Action[] allActions = {closeSchool};

Solution

  • Factory example:

    public class ActionFactory implements AbstractFactory<Action>{
    
      @Override
      public Action createAction(int type) {
        switch(type) {
          case 1: return new CloseShops();
          case 2: return new CloseAirports();
          default: return null;
      }
    
    }
    

    So, if you would want to differentiate between the types, and avoid having the developer himself building the objects, this is what to use. He can still pass additional parameters to the createAction method.

    List<Action> myActions = new ArrayList<>();
    ActionFactory fact = new ActionFactory();
    for ( int i = 0; i < 10; i++ ) {
      int type = assumeThisReadIntMethodExists();
      myActions.add(fact.createAction(type)); // this will add CloseShops or CloseAirports depending on the type passed
    }
    

    Builder example: The Builder pattern is more to avoid problems while creating instances. For example, for missing information.

    public class CloseShops {
      private final String nameOfShop;
    
      private CloseShops(String name) {
        this.nameOfShop = name; // as you can see, no check for null
        // it's always better to check for null before starting a constructor
      }
    
      public String getNameOfShop() {
        return nameOfShop;
      }
      // additional methods
    
      public static class Builder {
        private String name;
    
        public Builder withName(String name) {
          this.name = name;
          return this;
        }
    
        public Builder fromCloseShops(CloseShops original) {
          this.name = original.getNameOfShop();
          return this;
        }
    
        public CloseShops build() {
          assertNotNull("The name is mandatory", name);
          // this assert to avoid calling the constructor if the name is null
          return new CloseShops(this.name);
        }
    }
    

    This can be called like this:

    Action b = new CloseShops.Builder().withName("shopName").build();
    

    So, if it's to have less code, go for Factory.