Android设计模式--建造者模式
来源:互联网 发布:java goto特殊功能 编辑:程序博客网 时间:2024/05/16 16:00
- public class Person {
- private String name;
- private String password;
- private String birthday;
- private int age;
-
- public void setName(String name) {
- this.name = name.toUpperCase();
- }
-
- public String getName() {
- return this.name;
- }
-
- public void setPassword(String password) {
- this.password = password;
- }
-
- public String getPassword() {
- return this.password;
- }
-
- public void setBirthday(String birthday) {
- this.birthday = birthday;
- }
-
- public String getBirthday() {
- return this.birthday;
- }
-
- public void setAge(int age) {
- this.age = age;
- }
-
- public int getAge() {
- return this.age;
- }
-
- }
多数情况下,set方法与get方法联合使用,这就足够了。可是有时候,这个类还有其他的动作,比如说Person类还定义了登录动作,登录动作要对该用户的用户名和密码进行校验,如果用户名和密码输入正确,就返回登录成功。但实际业务往往不是这么简单,比如说用户登录期间可能还要输入短信验证码,然后在等待验证码短信时,用户密码因为某种原因发生变化(比如其他地方调用了setPassword方法),造成接收验证码之前密码校验通过,输入验证码之后密码校验反而失败。建造者模式
为此,建造者模式应运而生,它把对象的表现与构建分离开来,即把对象的使用分为两个步骤:第一步输入各种参数进行构建,此时只能设置属性不能操作业务动作;第二步根据构建好的对象开展业务动作,此时不能修改属性设置。就像建筑公司修桥造路,根据设计方案确定了水泥、砂石与钢筋的用量,然后按部就班加工建筑材料进行施工。如果施工过程中,有人私自减少水泥用量,或者把钢筋换成水泥,这个工程多半要成为豆腐渣工程了。建造者模式具体到代码实现上,是采用内部类的形式把构建部分分离出来,内部类的说明参见《Android开发笔记(八十六)几个特殊的类
》。即在Person类中再定义一个内部类Builder,由Builder类完成参数设置等构建操作。另外,为了确保对象的每个属性值只被赋值依次,可给各属性加上final修饰符,final的介绍参见《Android开发笔记(八十七)几个修饰关键字
》。下面是把Person类改造为建造者模式的代码例子:- public class Person {
- private final String name;
- private final String password;
- private final String birthday;
- private final int age;
-
- public String getName() {
- return this.name;
- }
-
- public String getPassword() {
- return this.password;
- }
-
- public String getBirthday() {
- return this.birthday;
- }
-
- public int getAge() {
- return this.age;
- }
-
- public void login() {
-
- }
-
- private Person(Builder builder) {
- this.name = builder.name;
- this.password = builder.password;
- this.birthday = builder.birthday;
- this.age = builder.age;
- }
-
- public static class Builder {
- private String name;
- private String password;
- private String birthday;
- private int age;
-
- public Builder setName(String name) {
- this.name = name.toUpperCase();
- return this;
- }
-
- public Builder setPassword(String password) {
- this.password = password;
- return this;
- }
-
- public Builder setBirthday(String birthday) {
- this.birthday = birthday;
- return this;
- }
-
- public Builder setAge(int age) {
- this.age = age;
- return this;
- }
-
- public Person build() {
- return new Person(this);
- }
-
- }
-
- }
初级用法
我们知道,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进行构建:- public static Uri withAppendedPath(Uri baseUri, String pathSegment) {
- Builder builder = baseUri.buildUpon();
- builder = builder.appendEncodedPath(pathSegment);
- return builder.build();
- }
其中buildUpon是个抽象方法,在具体类中需要重写。下面是StringUri类重写后的buildUpon方法,即可看到详细参数的建造过程:- public Builder buildUpon() {
- if (isHierarchical()) {
- return new Builder()
- .scheme(getScheme())
- .authority(getAuthorityPart())
- .path(getPathPart())
- .query(getQueryPart())
- .fragment(getFragmentPart());
- } else {
- return new Builder()
- .scheme(getScheme())
- .opaquePart(getSsp())
- .fragment(getFragmentPart());
- }
- }
Android中的使用场合
Android中会用到建造者模式的场合,一般是与异步操作有关的。因为异步操作的等待时间较长,极有可能在等待过程中发生属性值变更的情况,所以为了避免属性变化导致处理异常,就要引入建造者模式。常见的建造者模式应用场景包括:对话框AlertDialog、通知推送Notification、集合动画AnimatorSet,以及图片缓存框架等等。AlertDialog
AlertDialog的详细介绍参见《Android开发笔记(六十六)自定义对话框
》。下面是AlertDialog.Builder的用法代码例子:- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle("今天天气真好啊");
- builder.setMessage("我们去哪里玩玩吧");
- builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- showToast("是呀,我们去吃顿大餐吧");
- }
- });
- builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- showToast("真不巧,我已经约了别人啦");
- }
- });
- builder.setNeutralButton("中立", new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- showToast("嗯,今天我有事,明天可以吗");
- }
- });
- AlertDialog alert = builder.create();
- alert.show();
Notification
Notification的详细介绍参见《Android开发笔记(五十二)通知推送Notification
》。下面是Notification.Builder的用法代码例子:- Notification.Builder builder = new Notification.Builder(this);
- builder.setContentIntent(contentIntent)
- .setDeleteIntent(deleteIntent)
- .setUsesChronometer(true)
- .setProgress(100, 60, false)
- .setSubText("这里是副本")
- .setNumber(99)
- .setAutoCancel(false)
- .setSmallIcon(R.drawable.tt_s)
- .setTicker("提示文本")
- .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.tt_s))
- .setContentTitle("标题文本")
- .setContentText("内容文本");
- Notification notify = builder.build();
-
- NotificationManager notifyMgr = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
- notifyMgr.notify(R.string.app_name, notify);
AnimatorSet
AnimatorSet的详细介绍参见《Android开发笔记(九十六)集合动画与属性动画
》。下面是AnimatorSet.Builder的用法代码例子:- ObjectAnimator anim1 = ObjectAnimator.ofFloat(tv_text, "alpha", 1f, 0.1f, 1f, 0.5f, 1f);
- ObjectAnimator anim2 = ObjectAnimator.ofFloat(tv_text, "rotation", 0f, 360f);
- ObjectAnimator anim3 = ObjectAnimator.ofFloat(tv_text, "scaleY", 1f, 3f, 1f);
- ObjectAnimator anim4 = ObjectAnimator.ofFloat(tv_text, "translationY", 0f, 300f);
- AnimatorSet animSet = new AnimatorSet();
-
- AnimatorSet.Builder builder = animSet.play(anim1);
- builder.with(anim2).after(anim3).before(anim4);
- animSet.setDuration(5000);
- animSet.start();
图片缓存框架
图片缓存框架的详细介绍参见《Android开发笔记(七十七)图片缓存算法
》。两个常见的图片缓存框架Picasso和Universal-Image-Loader都实现了建造者模式的内部类Builder,下面是ImageLoaderConfiguration.Builder的用法代码例子:- ImageLoaderConfiguration.Builder mBuilder = new ImageLoaderConfiguration
- .Builder(this)
- .threadPoolSize(3)
- .threadPriority(Thread.NORM_PRIORITY - 2)
- .denyCacheImageMultipleSizesInMemory()
- .tasksProcessingOrder(QueueProcessingType.FIFO)
- .memoryCache(new UsingFreqLimitedMemoryCache(2 * 1024 * 1024))
- .memoryCacheSize(2 * 1024 * 1024)
- .memoryCacheSizePercentage(13)
- .memoryCacheExtraOptions(480, 800)
- .diskCache(new UnlimitedDiskCache(imageCacheDir))
- .diskCacheSize(50 * 1024 * 1024)
- .diskCacheFileCount(100)
- .imageDecoder(new BaseImageDecoder(false))
- .writeDebugLogs()
- ;
- ImageLoader.getInstance().init(mBuilder.build());