建造者模式
模式介绍 ##
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示
public class Person {
private int age;
private String name;
private String gender;
private String nation;
private boolean idLeader;
public Person(int age, String name, String gender, String nation, boolean idLeader) {
this.age = age;
this.name = name;
this.gender = gender;
this.nation = nation;
this.idLeader = idLeader;
}
}
可以看到Person对象是很复杂的,构建过程也很繁琐,我们可能在在new Person(…..)的时候根据字面意思很难明白这些个参数是什么含义,所以此时可以应用Builder设计模式
一个良好的示例,Universal-Image-Loader库配置图片显示选项的时候
public final class DisplayImageOptions {
private final int imageResOnLoading;
private final int imageResForEmptyUri;
......
private DisplayImageOptions(Builder builder) {
imageResOnLoading = builder.imageResOnLoading;
imageResForEmptyUri = builder.imageResForEmptyUri;
......
}
public boolean shouldShowImageOnLoading() {
return imageOnLoading != null || imageResOnLoading != 0;
}
public boolean shouldShowImageForEmptyUri() {
return imageForEmptyUri != null || imageResForEmptyUri != 0;
}
......
public static class Builder {
private int imageResOnLoading = 0;
private int imageResForEmptyUri = 0;
@Deprecated
public Builder showStubImage(int imageRes) {
imageResOnLoading = imageRes;
return this;
}
public Builder showImageForEmptyUri(int imageRes) {
imageResForEmptyUri = imageRes;
return this;
}
.....
public DisplayImageOptions build() {
return new DisplayImageOptions(this);
}
}
}
使用如下,简单明了,能瞬间明白每个参数配置的作用和含义
//显示图片的配置
DisplayImageOptions options = new DisplayImageOptions.Builder()
.showImageOnLoading(R.mipmap.ic_launcher)
.showImageOnFail(R.mipmap.ic_launcher)
.cacheInMemory(true)
.cacheOnDisk(true)
.bitmapConfig(Bitmap.Config.RGB_565)
.build();
优点与缺点
优点
* 良好的封装性, 使用建造者模式可以使客户端不必知道产品内部组成的细节;
* 建造者独立,容易扩展;
* 在对象创建过程中会使用到系统中的一些其它对象,这些对象在产品对象的创建过程中不易得到。
缺点
* 会产生多余的Builder对象以及Director对象,消耗内存;
* 对象的构建过程暴露。
模板方法模式
模式介绍
定义一个操作中的算法的框架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
1. 多个子类有公有的方法,并且逻辑基本相同时。
2. 重要、复杂的算法,可以把核心算法设计为模板方法,周边的相关细节功能则由各个子类实现。
3. 重构时,模板方法模式是一个经常使用的模式,把相同的代码抽取到父类中,然后通过钩子函数约束其行为。
在Android中,使用了模板方法且为我们熟知的一个典型类就是AsyncTask
了。 AsyncTask原理参考我之前写的 Android AsyncTask原理以及线程池概念
在使用AsyncTask时,我们都有知道耗时的方法要放在doInBackground(Params… params)中,在doInBackground之前如果还想做一些类似初始化的操作可以写在onPreExecute方法中,当doInBackground方法执行完成后,会执行onPostExecute方法,而我们只需要构建AsyncTask对象,然后执行execute方法即可。我们可以看到,它整个执行过程其实是一个框架,具体的实现都需要子类来完成。而且它执行的算法框架是固定的,调用execute后会依次执行onPreExecute,doInBackground,onPostExecute,当然你也可以通过onProgressUpdate来更新进度
再简单复习一下,基类AsyncTask定义了一套模板,什么时候调用onPostExecute什么时候调用doInBackground/onProgressUpdate,我们自定义自己AsyncTask的话,只需要复写这些方法就够了,而不需要关心核心的功能实现
public abstract class AsyncTask<Params, Progress, Result> {
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
Result result = doInBackground(mParams); //线程池中的子线程做后台任务
Binder.flushPendingCommands();
return postResult(result);
}
};
.....
}
private static class InternalHandler extends Handler {
public InternalHandler() {
super(Looper.getMainLooper());
}
@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
@Override
public void handleMessage(Message msg) {
AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:
// There is only one result
result.mTask.finish(result.mData[0]); //任务完成
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData); //进度更新
break;
}
}
}
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
protected abstract Result doInBackground(Params... params);
protected void onPreExecute() {
}
@SuppressWarnings({"UnusedDeclaration"})
protected void onPostExecute(Result result) {
}
@SuppressWarnings({"UnusedDeclaration"})
protected void onProgressUpdate(Progress... values) {
}
优点与缺点
优点
- 封装不变部分,扩展可变部分
- 提取公共部分代码,便于维护
缺点
- 模板方法会带来代码阅读的难度,会让心觉得难以理解
策略模式
策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。
注:针对同一类型操作,将复杂多样的处理方式分别开来,有选择的实现各自特有的操作。
- 针对同一类型问题的多种处理方式,仅仅是具体行为有差别时。
- 需要安全的封装多种同一类型的操作时。
- 出现同一抽象多个子类,而又需要使用if-else 或者 switch-case来选择时。
- Context:用来操作策略的上下文环境。
- Strategy : 策略的抽象。
- ConcreteStrategyA、ConcreteStrategyB : 具体的策略实现。
Android中动画的动态效果往往也取决于插值器Interpolator不同,我们只需要对Animation对象设置不同的Interpolator就可以实现不同的效果
动画原理参考 Android 补间动画原理
再简单过一下
public abstract class Animation implements Cloneable {
Interpolator mInterpolator;
public void setInterpolator(Interpolator i) {
mInterpolator = i;
}
public boolean getTransformation(long currentTime, Transformation outTransformation) {
........
final float interpolatedTime = mInterpolator.getInterpolation(normalizedTime);
applyTransformation(interpolatedTime, outTransformation);
........
}
//缩放动画,旋转动画需要重写该方法
protected void applyTransformation(float interpolatedTime, Transformation t) {
}
}
Animation就是充当操作策略的上下文环境对象,Interpolator策略的抽象,LinearInterpolator匀速/AccelerateDecelerateInterpolator加速减速插值器充当具体的策略实现。当然可以自定义插值器,然后应用在Animation上。
- 有木有发现其实整体来看就是个桥接模式,再从Animation抽象化角色来看,Animation又拓展为AlphaAnimation/RotateAnimation/ScaleAnimation等。
- Animation也可以看作是桥接模式中的抽象化角色,Interpolator充当实现化角色,Animation作为抽象话角色实例了对实现化Interpolator对象的引用