Build as Needed, or BAN, is a design pattern I've developed over the years for object oriented programming. It basically lays outs how to define the fields and associated accessors for your class. One of the major benefits is that it provides a simple way of defining the default or initial values for your fields, and makes sure that these values get used when needed. It also makes it very easy for sub classes to redefine these values. In addition, it makes it unneccessary to actually instantiate any values before they are actually needed, hence the name.
Contents |
Overview
The basic format is to define a private field, as usual, then have three associate methods, a setter, a getter, and an initializer. In addition, we also have someway of determining whether or not the field has been initialized yet. I used to just check to see if it was null, but there are many many flaws with this scheme. Now, I has a seperate boolean instance variable for each field, which is initialized to false, and is set to true once the field is initialized. Basically what happens is that the getter method checks this flag, and if it determines the field hasn't been
initialized yet, it invokes the initializer method to do so. In this way, anytime we call the getter, we can be sure the field will have been initialized before it gets back to us. Additionally, sub classes can easily just override the initializer method if they want different default values. The old method of assigning initial values in constructors or something, makes it very difficult to override, since the entire constructor would need to be overridden. Either that, or you would have to first call the super class constructor, and then replace the initial value of the field, which means it's being initialized twice, a waste of time. In addition, this way, we don't neccessarily have to initialize everything all at one time. In fact, if a field never gets accessed by the client code, we may never have to initialize it at all.
Note about init flags
An important note about this model (which is still evolving, naturally). This is in Java, I'm not sure about other languages, but it's worth looking into. When declaring the initialization flags, don't actually set their value to false. In Java, you don't need to because all values get an initial value assigned by the compiler (unlike in some other languages, like C for instance, in which the initial value is garbage and can't be relied on), and boolean values get initialized to false. That's why you don't need to, and here's a very good reason why you shouldn't: In certain, fairly common, situations, one of your build-as-needed fields will be accessed by a super-constructor, meaning the init flag will be set (to true). However, in at least some circumstances (at least whenthe super constructor is implicitly called), the fields in the lowest level class are not actually initialized until after the super constructor, so your init flags will end up getting set to true in the super constructor, and then reset to false afterwards, which means your field will be reinitialized, perhaps after it's already been set to some non-initial value.
Example
Take the following bad code for example:
abstract class Parent { //Constructor Parent(){ doSomethingAbstract(); } //Abstract method, to be overridden/implemented by sub classes public abstract void doSomethingAbstract(); }//End of class Parent class Child extends Parent { //Fields private String fSomething; protected boolean fnSomething = false; //Init flag for fSomething field //Constructors Child(){ //Super constructor implicitely called before we even reach this point //See what the REAL value of our field is System.out.println(fSomething); //See what we think it is System.out.println(getSomething()); } //BANs //Build-as-needed setter public void setSomething(String aSomething){ fSomething = aSomething; //assign value fnSomething = true; //set init flag } //BAN initializer protected String initSomething(){ return "initial_value"; } public String getSomething(){ //See if it's been initialized or set yet if(!fnSomething){ //If not, do so now setSomething(initSomething()); } return fSomething; } //Methods public void doSomethingAbstract(){ setSomething("Don't leave me!"); }
If we just create a new instance of the Child class now, the output is going to be this: Don't leave me! initial_value
What happens is that every instance of the class Child is also an instance of the class Parent, so when we create a new one, we need to call the constructor for the Parent class, which is called the super constructor from the point of view of the Child class. Since we haven't explicitly invoked a specific constructor of the Parent class, the JVM will implicitly invoke the default constructor (i.e., the one with no arguments). See "Java constructors" for more info on this. Now, for whatever reason, in the above situation, the JVM invokes this super constructor before initializing any of the instance variables in the Child class. So in the super constructor, we're setting the value of the fSomething field by invoking the setter method, which therefore sets the fnSomething to true. However, after we're done with the super constructor, the JVM will now initialize the instance variables in the Child class, including the fnSomething init flag, which has an initial value of false. So now, in our Child() constructor, when we ask for the value of the fSomething without using the accessor methods (which isn't a good idea, it's just to illustrate the point), it has the assigned value, "Don't leave me", which was set in the super constructor. However, since the init flag has been reset to false, our getter method thinks it's uninitialized, so it will re-initialize it to the default value, "initial_value".
Overhead
Yes, there is some overhead associated with doing things this way. For instance, anytime you query the field (assuming you're doing it through the getter like you should be), you have to do a boolean test. I suspect this is pretty minimal, but I'm planning to do some timed testing at some point.
This article is a stub.
