Android Common Design Patterns 10: Build Patterns

Keywords: Programming Android P4 Attribute OkHttp

For developers, design patterns can sometimes be a barrier, but design patterns can be very useful, beyond which you can move up a notch.In the development of Android, it is necessary to know some design patterns, because design patterns are ubiquitous in Android source code.For students who want to study design mode systematically, here is a Book recommended, Dahua Design Mode.

Android Common Design Mode Series:

Basic Object-Oriented Features
Object-oriented design principles
Singleton mode
Template mode
Adapter mode
Factory Mode
proxy pattern
Prototype mode
Policy Mode
Build mode
Observer mode
Decorator Mode
Mediation mode
facade

Build mode

Build mode is one of the most common design modes. Write a note to record my learning process and experience.

Start by understanding some of the definitions of Build patterns.

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

But after looking at this definition, there is no egg to use, and you still don't know what the Builder design pattern is.In this individual's attitude is to learn the design pattern such thing, do not care too much about its definition, the definition is often more abstract, the best example to learn it is through the sample code.

We present the Builder pattern through an example.Suppose there is a Car class where we build a large number of cars. There are many attributes in this Car class, such as color, price, brand, displacement, and so on, and we allow these values not to be set, that is, null, which is defined as follows.

public class Car  {
    Color color;
    double price;
    String brand;
    String displacement;

    public Color getColor() {
        return color;
    }

    public void setColor(Color color) {
        this.color = color;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public String getDisplacement() {
        return displacement;
    }

    public void setDisplacement(String displacement) {
        this.displacement = displacement;
    }
}

Then we might define a construction method for convenience.

public Car(Color color, double price, String brand, String displacement) {
 this.color = color;
 this.price = price;
 this.brand = brand;
 this. displacement = displacement;
}

Sometimes, you just want to pass some parameters, and you will define similar constructions as follows.

public Car(Color color) {
 this.color = color;
}
 public Car(Color color, double price) {
 this.color = color;
 this.price = price;
}
 public Car(Color color, double price, String brand) {
this.color = color;
 this.price = price;
 this.brand = brand;
} 

So you can create all the objects you need in this way

Person p2=new Person(Color.read);
Person p3=new Person(Color.blue,180000);
Person p4=new Person(Color.green,21180, "Xiao Peng");
Person p5=new Person(Color.white,17170,"Ferrari","4.0L"); 

You can imagine the disadvantage of creating this way. If all four parameters are of the same data type, what exactly do the parameters mean? That's readable.Another problem is that writing this constructor can be cumbersome when you have a lot of parameters, so if you try Builder mode from a different angle, you'll see that the code becomes readable all at once.

We add a static inner class Builder class to Car and modify the constructor of the Car class with the following code.

public class Car  {
    Color color;
    double price;
    String brand;
    String displacement;

    public Color getColor() {
        return color;
    }

    public void setColor(Color color) {
        this.color = color;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public String getDisplacement() {
        return displacement;
    }

    public void setDisplacement(String displacement) {
        this.displacement = displacement;
    }

    private Car(Builder builder) {
 this.color = builder.color;
 this.price = builder.price;
 this.brand = builder.brand;
 this. displacement = builder.displacement;
    }
    
    
    public static class Builder {

    Color color;
    double price;
    String brand;
    String displacement;
        
        public  Builder color(Color color){
            this.color=color;
            return  this;
        }
        public  Builder price(double price){
            this.price=price;
            return  this;
        }
        public  Builder brand(String brand){
            this.brand=brand;
            return  this;
        }
        public  Builder displacement(String displacement){
            this.displacement=displacement;
            return  this;
        }


        public Car build() {
            return new Car(this);
        }
    }
}

In this way, we will not be confused by the various inputs of the Car class constructor.
In addition, member functions in the Builder class return the Builder object itself, allowing it to support chain calls, greatly enhancing code readability.So we can create Car classes like this.

new Car.Builder().color(Color.BLUE)
                 .price(129800)
                 .pailiang("1.5T")
                 .brand("Xiao Peng")
                 .build();

Do you think the creation process will become so clear all of a sudden?The value corresponds to an attribute that is clear at a glance and is much more readable.

To summarize, let's summarize the main points of the build pattern:

1. Define a static internal class Builder, internal member variables are the same as external classes
2. The Builder class uses a series of methods to assign member variables and return the current object itself (this)
3. The Builder class provides a way to create an external class (build, create...)This method calls a private constructor of an external class internally, and the input is the internal class Builder
4. External classes provide a private constructor for internal classes to call, in which member variables are assigned values corresponding to the variable in the Builder object

Patterns are widely used

In fact, in Android, the Builder mode is also used a lot.For example, the creation of common dialogs

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(); 

Moreover, various third-party frameworks also make extensive use of the Builder model
For example, GsonBuilder in Gson, the code is too long to paste. You are interested in seeing the source code for yourself. Here is only how to use its Builder.

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

Take a look at OkHttp, the well-known network request framework

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

summary

Advantage

Builder mode is often used as the builder of a configuration class to separate the construction and representation of a configuration from the target class, to avoid being too many setter methods, and to hide internal details.A more common implementation of Builder mode is through chain calls, which make the code more concise and understandable.

shortcoming

References between internal and external classes may result in higher memory consumption, but this has little impact on current mobile memory.

Posted by BenGilbert on Wed, 25 Sep 2019 19:56:45 -0700