Android Design Patterns - Builder Patterns (Builder Patterns)

Posted by Dark-Hawk on Sun, 19 May 2019 13:02:52 +0200

Summary

Separating the construction of a complex object from its representation enables the same construction process to create different representations.

Raise a chestnut.

Here's an example of a pet hospital recording pet dog information

//Wang Wang's Information Class
public class Dog{   
    private int identifier;//number
    private String name;//Name
    private int age;//Age
    private int weight;//weight
    private String breed;//Varieties
    private boolean gender;//Gender, true: male; false: female
    private String sickness;//disease

    public void setIdentifier(int identifier){
         this.identifier=identifier;
    }

     public void setName(String name){
         this.name=name;
    }

     public void setAge(int age){
         this.age=age;
    }

     public void setWeight(int weight){
         this.weight=weight;
    }

     public void setBreed(int breed){
         this.breed=breed;
    }

     public void setGender(boolean gender){
         this.gender=gender;
    }
    public void setSickness(String sickness){
         this.sickness=sickness;
    }
}

Initialization, assignment:

//A new Wang came in.
Dog dog=new Dog;
dog.setIdentifier(2222);//Because it's an Erha, 2 exploded.
dog.setName("sijia");//Tear up a little expert
dog.setAge(3);
dog.setWeight(20);
dog.setBreed("Husky");
dog.setGender(true);
dog.setSickness("doubi");//This Husky is too funny. Can it be cured?

At last, we have worked out whether it is troublesome to assign value, and whether there is a simpler way, and some. Add a new method to the Dog class:

public void setDogInfo(int identifier,int String name,int age,int weight,String breed,boolean gender,String sickness){
    this.identifier=identifier;
    this.name=name;
    this.age=age;
    this.weight=weight;
    this.breed=breed;
    this.gender=gender;
    this.sickness=sickness;
}

Or add a new construction method:

public setDogInfo(int identifier,String name,int age,int weight,String breed,boolean gender,String sickness){
    this.identifier=identifier;
    this.name=name;
    this.age=age;
    this.weight=weight;
    this.breed=breed;
    this.gender=gender;
    this.sickness=sickness;
}

public setDogInfo(int identifier,String name){
    this.identifier=identifier;
    this.name=name;
}

public setDogInfo(int identifier,String name,int age,int weight){
    this.identifier=identifier;
    this.name=name;
    this.age=age;
    this.weight=weight;
}

Initialization, assignment

//such
Dog dog=new Dog();
dog.setDogInfo(2222,"sijia",3,20,"Husky",true,"doubi");

//Or so
Dog dog=new Dog(2222,"sijia",3,20,"Husky",true,"doubi");

//Or so
Dog dog=new Dog(2222,"sijia");

One line, but the meaning of numbers and strings is not clear at a glance, or you have to look at the definition. Adding new parameters will require modification of the definition, as well as modification of the place where the call is made.
And if there are more parameters, it will look more chaotic.

The builder pattern provides another solution by introducing the constructor Builder to accomplish the task of construction.

//Wang Wang's Information Class
public class Dog{   
    private int identifier;//number
    private String name;//Name
    private int age;//Age
    private int weight;//weight
    private String breed;//Varieties
    private boolean gender;//Gender, true: male; false: female
    private String sickness;//disease

    static class Builder{
        private Dog dog;

        public Builder(){
            dog=new Dog();
        }
        public Builder setIdentifier(int identifier){
             dog.identifier=identifier;
             return this;
    }

         public Builder setName(String name){
             dog.name=name;
             return this;
        }

         public Builder setAge(int age){
             dog.age=age;
             return this;
        }

         public Builder setWeight(int weight){
             dog.weight=weight;
             return this;
        }

         public Builder setBreed(int breed){
             dog.breed=breed;
             return this;
        }

         public Builder setGender(boolean gender){
             dog.gender=gender;
             return this;
        }
        public Builder setSickness(String sickness){
             dog.sickness=sickness;
             return this;
        }

        public Dog create(){
            return dog;
        }
    }
}

Builder is added to the object, and the method returned by Buidler to set parameters is Builder.
Now call:

Dog.Builder builder = new Dog.Builder();
Dog dog = builder.setIdentifier(2222).setName("sijia").setAge(3)
.setWeight(20).setBreed("Husky").setGender(true).setSickness("doubi")
.create();

In this way, each parameter is clearly defined, and directly connected to the end of the definition, eliminating duplicate code.  
It feels like we first get the Builder, then build all the parameters, and finally expose the constructed objects.  
It fits the schema definition: it separates the construction of a complex object from its representation, so that the same construction process can create different representations.

In fact, in Android, the Builder model is also widely used. For example, the creation of common dialog boxes

AlertDialog.Builder builder=new AlertDialog.Builder(this);
AlertDialog dialog=builder.setTitle("Title")
		.setIcon(android.R.drawable.ic_dialog_alert)
		.setView(R.layout.myview)
		.setPositiveButton(R.string.positive, new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {

			}
		})
		.setNegativeButton(R.string.negative, new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {

			}
		})
		.create();
dialog.show();

In fact, two common classes in java are also Builder patterns, StringBuilder and StringBuffer, but their implementation process is a little simplified.

Let's look for the application of Builder pattern in various frameworks.

For example, GsonBuilder in Gson, the code is too long to paste. I'm interested in seeing the source code for myself. Here's just how to use the Builder.

GsonBuilder builder=new GsonBuilder();
Gson gson=builder.setPrettyPrinting()
		.disableHtmlEscaping()
		.generateNonExecutableJson()
		.serializeNulls()
		.create();

There's also a Builder in EventBus, but it's not accessible externally, because its constructor is not public, but you can see its application in the EventBus class.

public static EventBusBuilder builder() {
	return new EventBusBuilder();
}
public EventBus() {
	this(DEFAULT_BUILDER);
}
EventBus(EventBusBuilder builder) {
	subscriptionsByEventType = new HashMap<Class<?>, CopyOnWriteArrayList<Subscription>>();
	typesBySubscriber = new HashMap<Object, List<Class<?>>>();
	stickyEvents = new ConcurrentHashMap<Class<?>, Object>();
	mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
	backgroundPoster = new BackgroundPoster(this);
	asyncPoster = new AsyncPoster(this);
	subscriberMethodFinder = new SubscriberMethodFinder(builder.skipMethodVerificationForClasses);
	logSubscriberExceptions = builder.logSubscriberExceptions;
	logNoSubscriberMessages = builder.logNoSubscriberMessages;
	sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
	sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
	throwSubscriberException = builder.throwSubscriberException;
	eventInheritance = builder.eventInheritance;
	executorService = builder.executorService;
}

Take another look at OkHttp, the famous network request framework

Request.Builder builder=new Request.Builder();
Request request=builder.addHeader("","")
	.url("")
	.post(body)
	.build();

It can be seen that a large number of frameworks use the Builder model. Finally, sum up.

  • Define a static internal class Builder, internal member variables are the same as external classes
  • The Builder class uses a series of methods for assigning member variables and returns the current object itself (this)
  • The Builder class provides a build method or create method for creating the corresponding external class, which calls a private constructor of the external class internally, whose parameter is the internal class Builder.
  • External classes provide a private constructor for internal classes to call, in which member variables are assigned to the corresponding value in the Builder object.

Topics: Android Java OkHttp network