English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
This article illustrates the Builder pattern in Android programming design patterns. Share it with everyone for reference, as follows:
Chapter 1: Introduction
The Builder pattern is a creational pattern that creates a complex object step by step. It allows users to control the construction process of the object more finely without knowing the internal construction details. This pattern is designed to decouple the process of constructing complex objects from their components, so that the construction process and the representation of components are isolated.
Because a complex object has many components, for example, a car has wheels, steering wheels, engines, and various small parts, etc. How to assemble these components into a car, this assembly process is very long and complex. For this kind of situation, in order to hide the implementation details from the outside during the construction process, the Builder pattern can be used to separate the components and assembly process, making the construction process and components can be freely expanded, and the coupling between them is reduced to the lowest.
Chapter 2: Definition
Separate the construction of a complex object from its representation, so that the same construction process can create different representations.
Chapter 3: Use Cases
(1When the same method, with different execution sequences, produces different event results.
(2When multiple components or parts can be assembled into an object, but the resulting running results are not the same.
(3When the product class is very complex, or the calling sequence in the product class produces different effects, the Builder pattern is very suitable at this time.
(4When initializing an object is particularly complex, such as having many parameters and many of them have default values.
Chapter 4: UML Class Diagram of Builder Pattern
Role Introduction:
Product product class——The abstract class of products;
Builder——Abstract Builder class, standardizes the assembly of products, generally implemented by subclasses to achieve specific assembly processes;
ConcreateBuilder——Specific Builder class;
Director——Unified assembly process;
5. Simple Implementation of Builder Pattern
The assembly process of the computer is relatively complex, and the assembly sequence is not fixed. For ease of understanding, we simplify the assembly process of the computer to build the host, set the operating system, and set the display3parts, and then build the computer object through Director and specific Builder.
Example code:
/** * Computer abstract class, that is the Product role */ public abstract class Computer { protected String mBoard; protected String mDisplay; protected String mOS; protected Computer(){} /** * Set the motherboard * @param board */ public void setBoard(String board){ this.mBoard = board; } /** * Set the display * @param display */ public void setDisplay(String display){ this.mDisplay = display; } /** * Set operating system */ public abstract void setOS(); @Override public String toString(){ return "Computer [mBoard=" + mBoard + ", mDisplay=" + mDisplay + ", mOS=" + mOS + "]"; } }
/** * A specific Computer class, Macbook */ public class Macbook extends Computer { protected Macbook(){} @Override public void setOS() { mOS = "Mac OS X 10"; } }
/** * Abstract Builder class */ public abstract class Builder { /** * Set the host * @param board */ public abstract void buildBoard(String board); /** * Set the display * @param display */ public abstract void buildDisplay(String display); /** * Set operating system */ public abstract void buildOS(); /** * Create Computer * @return */ public abstract Computer create(); }
/** * Specific Builder class, MacbookBuilder */ public class MacbookBuilder extends Builder { private Computer mComputer = new Macbook(); @Override public void buildBoard(String board) { mComputer.setBoard(board); } @Override public void buildDisplay(String display) { mComputer.setDisplay(display); } @Override public void buildOS() { mComputer.setOS(); } @Override public Computer create() { return mComputer; } }
/** * Director class, responsible for constructing Computer */ public class Director { Builder mBuilder = null; public Director(Builder builder){ mBuilder = builder; } /** * Build object * @param board Motherboard * @param display Display */ public void construct(String board, String display){ mBuilder.buildBoard(board); mBuilder.buildDisplay(display); mBuilder.buildOS(); } }
/** * Test code */ public class Test { public static void main(String[] args){ //Builder Builder builder = new MacbookBuilder(); //Director Director pcDirector = new Director(builder); //Encapsulation construction process pcDirector.construct("Intel motherboard","Retina display"); //Build a computer and output relevant information System.out.println("Computer Info : ") + builder.create().toString()); } }
Output result:
Computer Info : Computer [mBoard=Intel motherboard, mDisplay=Retina display, mOS=Mac OS X 10]
In the above example, the specific MacbookBuilder is used to build the Macbook object, while the Director encapsulates the process of building complex product objects, hiding the construction details. Together, Builder and Director separate the construction of a complex object from its representation, allowing the same construction process to create different objects.
It is worth noting that in the actual development process, the Director role is often omitted. Instead, a Builder is directly used for object assembly, which is usually chained invocation. The key point is that each setter method returns itself, that is, return this, which allows the setter method to be chained. The code is roughly as follows:
new TestBuilder() .setA("A") .create();
This form not only removes the Director role, but also makes the entire structure simpler, and can have more fine-grained control over the assembly process of the Product object.
Variants of Builder Pattern - Chained Invocation
Example code:
public class User { private final String name; //Required private final String cardID; //Required private final int age; //Optional private final String address; //Optional private final String phone; //Optional private User(UserBuilder userBuilder){ this.name=userBuilder.name; this.cardID=userBuilder.cardID; this.age=userBuilder.age; this.address=userBuilder.address; this.phone=userBuilder.phone; } public String getName() { return name; } public String getCardID() { return cardID; } public int getAge() { return age; } public String getAddress() {}} return address; } public String getPhone() { return phone; } public static class UserBuilder{ private final String name; private final String cardID; private int age; private String address; private String phone; public UserBuilder(String name,String cardID){ this.name=name; this.cardID=cardID; } public UserBuilder age(int age){ this.age=age; return this; } public UserBuilder address(String address){ this.address=address; return this; } public UserBuilder phone(String phone){ this.phone=phone; return this; } public User build(){ return new User(this); } } }
Points to note:
The constructor of the User class is private, so the caller cannot directly create a User object.
The properties of the User class are immutable. All properties are added with the final modifier, and values are set in the constructor. Moreover, only getters are provided to the outside.
The constructor of the Builder inner class only accepts mandatory parameters, and these mandatory parameters are marked with the final modifier.
Calling method:
new User.UserBuilder("Jack","10086) .age(25) .address("GuangZhou") .phone("13800138000") .build();
Compared to the previous ones through the constructor and setter/There are two ways to use getter methods, which are more readable. The only possible problem is that it may generate extra Builder objects, consuming memory. However, in most cases, our Builder inner class uses the static modifier (static), so this issue is not significant.
About thread safety
The Builder pattern is not thread-safe. If you need to check the validity of a parameter within the Builder inner class, it is necessary to check it after the object is created.
Correct example:
public User build() { User user = new user(this); if (user.getAge() > 120) { throw new IllegalStateException("Age out of range"); // Thread-safe } return user; }
Error example:
public User build() { if (age > 120) { throw new IllegalStateException("Age out of range"); // Not thread-safe } return new User(this); }
Example of using Builder pattern
1AlertDialog.Builder in Android
private void showDialog(){ AlertDialog.Builder builder=new AlertDialog.Builder(context); builder.setIcon(R.drawable.icon); builder.setTitle("Title"); builder.setMessage("Message"); builder.setPositiveButton("Button1" @Override public void onClick(DialogInterface dialog, int which) { //TODO } }); builder.setNegativeButton("Button2" @Override public void onClick(DialogInterface dialog, int which) { //TODO } }); builder.create().show(); }
2OkHttpClient creation in OkHttp
OkHttpClient okHttpClient = new OkHttpClient.Builder() .cache(getCache()) .addInterceptor(new HttpCacheInterceptor()) .addInterceptor(new LogInterceptor()) .addNetworkInterceptor(new HttpRequestInterceptor()) .build();
3Retrofit object creation in Retrofit
Retrofit retrofit = new Retrofit.Builder() .client(createOkHttp()) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .baseUrl(BASE_URL) .build();
It can be seen that in actual use, the Director role is omitted, and in many framework source codes, when it comes to the Builder pattern, most of them are not the classic GOF Builder pattern, but choose the simpler one.
8. Advantages and Disadvantages
Advantages:
Good encapsulation makes it unnecessary for the client to know the details of the internal implementation of the product
Builder is independent and has strong extensibility
Disadvantages:
Excessive Builder objects and Director objects are created, consuming memory
Readers who are interested in more content related to Android can check the special topics on this site: 'Android Development入门与进阶教程', 'Android Debugging Skills and Common Problem Solving Methods Summary', 'Summary of Android Basic Component Usage', 'Summary of Android View View Skills', 'Summary of Android Layout Layout Skills', and 'Summary of Android Control Usage'.
I hope the content described in this article will be helpful to everyone's Android program design.
Declaration: The content of this article is from the Internet, and the copyright belongs to the original author. The content is contributed and uploaded by Internet users spontaneously. This website does not own the copyright, has not been manually edited, and does not assume any relevant legal liability. If you find any content suspected of copyright infringement, please send an email to: notice#w3Please report any violations by email to codebox.com (replace # with @), and provide relevant evidence. Once verified, this site will immediately delete the suspected infringing content.