Android设计模式--建造者模式

来源:互联网 发布:java goto特殊功能 编辑:程序博客网 时间:2024/05/16 16:00
[java] view plain copy
  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();  //用户名不区分大小写,统一转为大写  
  9.     }  
  10.       
  11.     public String getName() {  
  12.         return this.name;  
  13.     }  
  14.   
  15.     public void setPassword(String password) {  
  16.         this.password = password; //这里可补充加密操作  
  17.     }  
  18.       
  19.     public String getPassword() {  
  20.         return this.password; //这里可补充解密操作  
  21.     }  
  22.   
  23.     public void setBirthday(String birthday) {  
  24.         this.birthday = birthday; //这里可根据生日计算年龄,即自动对age字段赋值  
  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. }  

多数情况下,set方法与get方法联合使用,这就足够了。可是有时候,这个类还有其他的动作,比如说Person类还定义了登录动作,登录动作要对该用户的用户名和密码进行校验,如果用户名和密码输入正确,就返回登录成功。但实际业务往往不是这么简单,比如说用户登录期间可能还要输入短信验证码,然后在等待验证码短信时,用户密码因为某种原因发生变化(比如其他地方调用了setPassword方法),造成接收验证码之前密码校验通过,输入验证码之后密码校验反而失败。


建造者模式

为此,建造者模式应运而生,它把对象的表现与构建分离开来,即把对象的使用分为两个步骤:第一步输入各种参数进行构建,此时只能设置属性不能操作业务动作;第二步根据构建好的对象开展业务动作,此时不能修改属性设置。就像建筑公司修桥造路,根据设计方案确定了水泥、砂石与钢筋的用量,然后按部就班加工建筑材料进行施工。如果施工过程中,有人私自减少水泥用量,或者把钢筋换成水泥,这个工程多半要成为豆腐渣工程了。


建造者模式具体到代码实现上,是采用内部类的形式把构建部分分离出来,内部类的说明参见《Android开发笔记(八十六)几个特殊的类》。即在Person类中再定义一个内部类Builder,由Builder类完成参数设置等构建操作。另外,为了确保对象的每个属性值只被赋值依次,可给各属性加上final修饰符,final的介绍参见《Android开发笔记(八十七)几个修饰关键字》。下面是把Person类改造为建造者模式的代码例子:
[java] view plain copy
  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; //这里可补充解密操作  
  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.         //这里补充登录操作的代码  
  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();  //用户名不区分大小写,统一转为大写  
  42.             return this;  
  43.         }  
  44.   
  45.         public Builder setPassword(String password) {  
  46.             this.password = password; //这里可补充加密操作  
  47.             return this;  
  48.         }  
  49.   
  50.         public Builder setBirthday(String birthday) {  
  51.             this.birthday = birthday; //这里可根据生日计算年龄,即自动对age字段赋值  
  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. }  


初级用法

我们知道,java中构建字符串主要有下列几种方式:
1、几个字符串使用“+”连接;
2、调用String.format方法进行字符串格式化;
3、使用StringBuilder类构造字符串;
其中第三种方式便是建造者模式的初级模型。通过调用StringBuilder类的append、insert、delete等方法修改内容,最后调用toString方法输出构造完的字符串。

当然StringBuilder是单独的类,并非String类的内部类,而且也不是操作具体的属性,所以StringBuilder不是真正意义上的建造者模式。与StringBuilder比较类似,同时又采用建造者模式的,这个例子是Uri.Builder。不过Uri内部已经封装好了建造过程,没有向外开放Builder的使用,通常我们调用Uri.parse或者Uri.withAppendedPath方法即可获得Uri实例。

查看withAppendedPath方法的源码,可看到其内部采用了Builder进行构建:
[java] view plain copy
  1. public static Uri withAppendedPath(Uri baseUri, String pathSegment) {  
  2.     Builder builder = baseUri.buildUpon();  
  3.     builder = builder.appendEncodedPath(pathSegment);  
  4.     return builder.build();  
  5. }  

其中buildUpon是个抽象方法,在具体类中需要重写。下面是StringUri类重写后的buildUpon方法,即可看到详细参数的建造过程:
[java] view plain copy
  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. }  


Android中的使用场合

Android中会用到建造者模式的场合,一般是与异步操作有关的。因为异步操作的等待时间较长,极有可能在等待过程中发生属性值变更的情况,所以为了避免属性变化导致处理异常,就要引入建造者模式。常见的建造者模式应用场景包括:对话框AlertDialog、通知推送Notification、集合动画AnimatorSet,以及图片缓存框架等等。


AlertDialog

AlertDialog的详细介绍参见《Android开发笔记(六十六)自定义对话框》。下面是AlertDialog.Builder的用法代码例子:
[java] view plain copy
  1. AlertDialog.Builder builder = new AlertDialog.Builder(this);  
  2. builder.setTitle("今天天气真好啊");  
  3. builder.setMessage("我们去哪里玩玩吧");  
  4. builder.setPositiveButton("确定"new DialogInterface.OnClickListener() {  
  5.     @Override  
  6.     public void onClick(DialogInterface dialog, int which) {  
  7.         showToast("是呀,我们去吃顿大餐吧");  
  8.     }  
  9. });  
  10. builder.setNegativeButton("取消"new DialogInterface.OnClickListener() {  
  11.     @Override  
  12.     public void onClick(DialogInterface dialog, int which) {  
  13.         showToast("真不巧,我已经约了别人啦");  
  14.     }  
  15. });  
  16. builder.setNeutralButton("中立"new DialogInterface.OnClickListener() {  
  17.     @Override  
  18.     public void onClick(DialogInterface dialog, int which) {  
  19.         showToast("嗯,今天我有事,明天可以吗");  
  20.     }  
  21. });  
  22. AlertDialog alert = builder.create();  
  23. alert.show();  


Notification

Notification的详细介绍参见《Android开发笔记(五十二)通知推送Notification》。下面是Notification.Builder的用法代码例子:
[java] view plain copy
  1. Notification.Builder builder = new Notification.Builder(this);  
  2. builder.setContentIntent(contentIntent)  
  3.         .setDeleteIntent(deleteIntent)  
  4.         .setUsesChronometer(true)  
  5.         .setProgress(10060false)  
  6.         .setSubText("这里是副本")  
  7.         .setNumber(99)  
  8.         .setAutoCancel(false)  
  9.         .setSmallIcon(R.drawable.tt_s)  
  10.         .setTicker("提示文本")  
  11.         .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.tt_s))  
  12.         .setContentTitle("标题文本")  
  13.         .setContentText("内容文本");  
  14. Notification notify = builder.build();  
  15.   
  16. NotificationManager notifyMgr = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);  
  17. notifyMgr.notify(R.string.app_name, notify);  


AnimatorSet

AnimatorSet的详细介绍参见《Android开发笔记(九十六)集合动画与属性动画》。下面是AnimatorSet.Builder的用法代码例子:
[java] view plain copy
  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不提供create或build方法  
  7. AnimatorSet.Builder builder = animSet.play(anim1);  
  8. builder.with(anim2).after(anim3).before(anim4);// anim3先执行,然后再同步执行anim1、anim2,最后执行anim4  
  9. animSet.setDuration(5000);  
  10. animSet.start();  


图片缓存框架

图片缓存框架的详细介绍参见《Android开发笔记(七十七)图片缓存算法》。两个常见的图片缓存框架Picasso和Universal-Image-Loader都实现了建造者模式的内部类Builder,下面是ImageLoaderConfiguration.Builder的用法代码例子:
[java] view plain copy
  1. ImageLoaderConfiguration.Builder mBuilder = new ImageLoaderConfiguration    
  2.     .Builder(this)  
  3.     .threadPoolSize(3//线程池内加载的数量    
  4.     .threadPriority(Thread.NORM_PRIORITY - 2//设置当前线程的优先级  
  5.     .denyCacheImageMultipleSizesInMemory() //拒绝缓存同一图片的多个尺寸版本  
  6.     .tasksProcessingOrder(QueueProcessingType.FIFO) //队列的排队算法,默认FIFO。FIFO表示先进先出,LIFO表示后进先出  
  7.     .memoryCache(new UsingFreqLimitedMemoryCache(2 * 1024 * 1024)) //你可以通过自己的内存缓存实现    
  8.     .memoryCacheSize(2 * 1024 * 1024//使用的内存大小  
  9.     .memoryCacheSizePercentage(13//使用的内存百分比  
  10.     .memoryCacheExtraOptions(480800//设置内存中图片的长宽   
  11.     .diskCache(new UnlimitedDiskCache(imageCacheDir)) //自定义磁盘的路径  
  12.     .diskCacheSize(50 * 1024 * 1024//使用的磁盘大小  
  13.     .diskCacheFileCount(100//磁盘的文件数量上限  
  14.     .imageDecoder(new BaseImageDecoder(false)) //对图片解码,如需缩放或旋转可在此处理  
  15.     .writeDebugLogs() //打印调试日志。上线时需要去掉该方法  
  16.     ;  
  17. ImageLoader.getInstance().init(mBuilder.build());  

原创粉丝点击