Android Design Patterns--Builder Patterns

Keywords: Android Attribute Fragment Java

  1. public class Person {  
  2.     private String name;  
  3.     private String password;  
  4.     private String birthday;  
  5.     private int age;  
  6.   
  7.     public void setName(String name) {  
  8.         this.name = name.toUpperCase();  //User names are case-insensitive and uniformly capitalized  
  9.     }  
  10.       
  11.     public String getName() {  
  12.         return this.name;  
  13.     }  
  14.   
  15.     public void setPassword(String password) {  
  16.         this.password = password; //Encryption operations can be supplemented here.  
  17.     }  
  18.       
  19.     public String getPassword() {  
  20.         return this.password; //Here you can supplement the decryption operation  
  21.     }  
  22.   
  23.     public void setBirthday(String birthday) {  
  24.         this.birthday = birthday; //Here, age can be calculated based on birthday, i.e., the age field can be automatically assigned.  
  25.     }  
  26.       
  27.     public String getBirthday() {  
  28.         return this.birthday;  
  29.     }  
  30.   
  31.     public void setAge(int age) {  
  32.         this.age = age;  
  33.     }  
  34.       
  35.     public int getAge() {  
  36.         return this.age;  
  37.     }  
  38.       
  39. }  

In most cases, the combination of set and get methods is sufficient. Sometimes, however, there are other actions in this class. For example, the Person class also defines the login action. The login action verifies the user's username and password. If the user's name and password are entered correctly, the login will be successful. But the actual business is often not so simple. For example, the user may enter a short message authentication code during login. Then, when waiting for the short message of authentication code, the user password changes for some reason (for example, setPassword method is called elsewhere), which causes the password verification to pass before receiving authentication code, but fails after entering authentication code.


Builder pattern

For this reason, the builder model emerges as the times require. It separates the representation and construction of objects, that is to say, the use of objects is divided into two steps: the first step is to input various parameters to construct, at this time only setting attributes can not operate business actions; the second step is to carry out business actions according to the constructed objects, and at this time can not modify property settings. Just like the construction company repairing bridges and roads, the amount of cement, sand and reinforcement is determined according to the design scheme, and then the construction materials are processed step by step. If someone reduces the amount of cement or replaces steel bars with cement in the process of construction, the project will mostly become tofu dregs project.


The builder pattern is specific to code implementation. It uses the form of internal classes to separate the building parts. See the description of internal classes.< Android Development Notes (86) Several Special Classes " That is to say, an internal class Builder is defined in the Person class, and the Builder class completes the parameter setting and other construction operations. In addition, in order to ensure that each attribute value of an object is assigned in order only, final modifiers can be added to each attribute. See the introduction of final.< Android Development Notes (87) Several Modified Keywords " Following is a code example of transforming the Person class into the builder pattern:
  1. public class Person {  
  2.     private final String name;  
  3.     private final String password;  
  4.     private final String birthday;  
  5.     private final int age;  
  6.   
  7.     public String getName() {  
  8.         return this.name;  
  9.     }  
  10.   
  11.     public String getPassword() {  
  12.         return this.password; //Here you can supplement the decryption operation  
  13.     }  
  14.   
  15.     public String getBirthday() {  
  16.         return this.birthday;  
  17.     }  
  18.   
  19.     public int getAge() {  
  20.         return this.age;  
  21.     }  
  22.       
  23.     public void login() {  
  24.         //Here is the code to add the login operation  
  25.     }  
  26.       
  27.     private Person(Builder builder) {  
  28.         this.name = builder.name;  
  29.         this.password = builder.password;  
  30.         this.birthday = builder.birthday;  
  31.         this.age = builder.age;  
  32.     }  
  33.       
  34.     public static class Builder {  
  35.         private String name;  
  36.         private String password;  
  37.         private String birthday;  
  38.         private int age;  
  39.   
  40.         public Builder setName(String name) {  
  41.             this.name = name.toUpperCase();  //User names are case-insensitive and uniformly capitalized  
  42.             return this;  
  43.         }  
  44.   
  45.         public Builder setPassword(String password) {  
  46.             this.password = password; //Encryption operations can be supplemented here.  
  47.             return this;  
  48.         }  
  49.   
  50.         public Builder setBirthday(String birthday) {  
  51.             this.birthday = birthday; //Here, age can be calculated based on birthday, i.e., the age field can be automatically assigned.  
  52.             return this;  
  53.         }  
  54.   
  55.         public Builder setAge(int age) {  
  56.             this.age = age;  
  57.             return this;  
  58.         }  
  59.           
  60.         public Person build() {  
  61.             return new Person(this);  
  62.         }  
  63.           
  64.     }  
  65.       
  66. }  


Primary usage

As we know, there are several ways to construct strings in java:
1. Several strings are connected by "+".
2. Call String.format method for string formatting;
3. StringBuilder class is used to construct strings.
The third is the primary model of the builder model. By calling append, insert, delete of StringBuilder class to modify the content, and finally calling toString method to output the constructed string.

Of course, StringBuilder is a separate class, not an internal class of String class, and it is not an operation of specific attributes, so StringBuilder is not a real builder pattern. Similar to StringBuilder, but also using the builder model, this example is Uri.Builder. However, the construction process has been encapsulated in Uri, and the use of Builder is not open to the outside world. Usually we can get Uri instances by calling Uri.parse or Uri.withAppendedPath methods.

Looking at the source code of the withAppendedPath method, you can see that it is built internally with Builder:
  1. public static Uri withAppendedPath(Uri baseUri, String pathSegment) {  
  2.     Builder builder = baseUri.buildUpon();  
  3.     builder = builder.appendEncodedPath(pathSegment);  
  4.     return builder.build();  
  5. }  

BuilUpon is an abstract method that needs to be rewritten in concrete classes. Following is the rebuilt buildUpon method of StringUri class. You can see the construction process of the detailed parameters.
  1. public Builder buildUpon() {  
  2.     if (isHierarchical()) {  
  3.         return new Builder()  
  4.                 .scheme(getScheme())  
  5.                 .authority(getAuthorityPart())  
  6.                 .path(getPathPart())  
  7.                 .query(getQueryPart())  
  8.                 .fragment(getFragmentPart());  
  9.     } else {  
  10.         return new Builder()  
  11.                 .scheme(getScheme())  
  12.                 .opaquePart(getSsp())  
  13.                 .fragment(getFragmentPart());  
  14.     }  
  15. }  


Use occasions in Android

In Android, builder mode is used, which is usually related to asynchronous operation. Because the waiting time of asynchronous operation is long, it is very likely that the attribute values will change during the waiting process. In order to avoid the exception caused by the attribute changes, the builder mode should be introduced. Common application scenarios for builder mode include dialog box Alert Dialog, notification push Notification, collection animation Animator Set, and image caching framework.


AlertDialog

For a detailed introduction to Alert Dialog, see< Android Development Notes (66) Custom Dialog Box " Below is an example of AlertDialog.Builder's usage code:
  1. AlertDialog.Builder builder = new AlertDialog.Builder(this);  
  2. builder.setTitle("It's a lovely day today.");  
  3. builder.setMessage("Where shall we play?");  
  4. builder.setPositiveButton("Sure?"new DialogInterface.OnClickListener() {  
  5.     @Override  
  6.     public void onClick(DialogInterface dialog, int which) {  
  7.         showToast("Yeah, let's go for a big meal.");  
  8.     }  
  9. });  
  10. builder.setNegativeButton("cancel"new DialogInterface.OnClickListener() {  
  11.     @Override  
  12.     public void onClick(DialogInterface dialog, int which) {  
  13.         showToast("Unfortunately, I've already made an appointment with someone else.");  
  14.     }  
  15. });  
  16. builder.setNeutralButton("neutral"new DialogInterface.OnClickListener() {  
  17.     @Override  
  18.     public void onClick(DialogInterface dialog, int which) {  
  19.         showToast("Well, I have something to do today. Is tomorrow OK?");  
  20.     }  
  21. });  
  22. AlertDialog alert = builder.create();  
  23. alert.show();  


Notification

For a detailed introduction to Notification, see< Android Development Notes (52) Notification Notification " Here is an example of Notification.Builder's usage code:
  1. Notification.Builder builder = new Notification.Builder(this);  
  2. builder.setContentIntent(contentIntent)  
  3.         .setDeleteIntent(deleteIntent)  
  4.         .setUsesChronometer(true)  
  5.         .setProgress(10060false)  
  6.         .setSubText("Here is a copy.")  
  7.         .setNumber(99)  
  8.         .setAutoCancel(false)  
  9.         .setSmallIcon(R.drawable.tt_s)  
  10.         .setTicker("Prompt text")  
  11.         .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.tt_s))  
  12.         .setContentTitle("Title Text")  
  13.         .setContentText("Content text");  
  14. Notification notify = builder.build();  
  15.   
  16. NotificationManager notifyMgr = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);  
  17. notifyMgr.notify(R.string.app_name, notify);  


AnimatorSet

Detailed introduction to AnimatorSet< Android Development Notes (96) Collection Animation and Attribute Animation " Here is an example of the usage code of AnimatorSet.Builder:
  1. ObjectAnimator anim1 = ObjectAnimator.ofFloat(tv_text, "alpha", 1f, 0.1f, 1f, 0.5f, 1f);  
  2. ObjectAnimator anim2 = ObjectAnimator.ofFloat(tv_text, "rotation", 0f, 360f);  
  3. ObjectAnimator anim3 = ObjectAnimator.ofFloat(tv_text, "scaleY", 1f, 3f, 1f);  
  4. ObjectAnimator anim4 = ObjectAnimator.ofFloat(tv_text, "translationY", 0f, 300f);  
  5. AnimatorSet animSet = new AnimatorSet();  
  6. //AnimatorSet.Builder does not provide create or build methods  
  7. AnimatorSet.Builder builder = animSet.play(anim1);  
  8. builder.with(anim2).after(anim3).before(anim4);//anim3 executes first, then anim1 and anim2 are executed synchronously, finally anim4 is executed  
  9. animSet.setDuration(5000);  
  10. animSet.start();  


Image Caching Framework

For a detailed introduction to the picture caching framework, see< Android Develops Note (77) Picture Caching Algorithms " Two common image caching frameworks, Picasso and Universal-Image-Loader, implement the Builder internal class of the builder pattern. Here is an example of the use code of the ImageLoader Configuration.Builder:
  1. ImageLoaderConfiguration.Builder mBuilder = new ImageLoaderConfiguration    
  2.     .Builder(this)  
  3.     .threadPoolSize(3//Number of loads in the thread pool  
  4.     .threadPriority(Thread.NORM_PRIORITY - 2//Setting the priority of the current thread  
  5.     .denyCacheImageMultipleSizesInMemory() //Refuse to cache multiple sizes of the same image  
  6.     .tasksProcessingOrder(QueueProcessingType.FIFO) //Queuing algorithm of queue, default FIFO. FIFO denotes FIFO and LIFO denotes FIFO.  
  7.     .memoryCache(new UsingFreqLimitedMemoryCache(2 * 1024 * 1024)) //You can implement it through your own memory cache.  
  8.     .memoryCacheSize(2 * 1024 * 1024//Memory size used  
  9.     .memoryCacheSizePercentage(13//Percentage of memory used  
  10.     .memoryCacheExtraOptions(480800//Set the lengths and widths of pictures in memory  
  11.     .diskCache(new UnlimitedDiskCache(imageCacheDir)) //Custom Disk Path  
  12.     .diskCacheSize(50 * 1024 * 1024//Disk size used  
  13.     .diskCacheFileCount(100//Upper limit on the number of files on disk  
  14.     .imageDecoder(new BaseImageDecoder(false)) //For image decoding, zoom or rotate can be done here.  
  15.     .writeDebugLogs() //Print debug log. This method needs to be removed when on-line  
  16.     ;  
  17. ImageLoader.getInstance().init(mBuilder.build());  

Posted by darthbutternutz on Sat, 18 May 2019 14:00:52 -0700