基本概念
策略模式是一种把算法和对象分离开的设计模式。
策略模式其实是多态的一种表现。在实现一个功能时,根据不同的业务需求有不同的算法,如果是简单操作,那么使用if else或者switch case即可完成分支处理。但是这么做的可扩展性太差,尤其算法比较复杂的时候更是如此;而且也不具备灵活性,难以按照用户需求实现细节定制。策略模式的出现就是为了解决这些问题,它的好处有:
1、消除了if else或者switch case的分支判断;
2、采用独立的算法类,易于根据新需求进行扩展;
3、方便开发者对算法细节做自定义处理;
4、允许随时设定策略,即可在构造时设置,也可用专门的set方法设置,还可在执行时设置算法;
Android中的使用场合
Android开发中用到策略模式的地方也不少,常见的有排序算法、字符串显示策略、动画插值器和估值器等等。
排序算法
java有自带了对两类数据结构的排序方法,一类是数组的排序,使用的是Arrays类的sort方法;另一类是队列的排序,使用的是Collections类的sort方法。sort方法中的参数就有对元素进行排序的算法类Comparator,可由开发者自定义算法比较两个元素的大小。其中有关java队列的介绍参见《 Android开发笔记(二十六)Java的容器类》,下面是对数组和队列进行排序的代码示例:
public static void main(String[] arg) {
String[] strArray = {"abc", "aaa", "abb", "tgy", "ctr"};
System.out.println("before sort");
for (int i=0; i<strArray.length; i++) {
System.out.println("strArray["+i+"]="+strArray[i]);
}
Arrays.sort(strArray, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
});
System.out.println("after sort");
for (int i=0; i<strArray.length; i++) {
System.out.println("strArray["+i+"]="+strArray[i]);
}
ArrayList<Integer> intList = new ArrayList<Integer>();
intList.add(10);
intList.add(4);
intList.add(7);
intList.add(1);
intList.add(3);
System.out.println("before sort");
for (int i=0; i<intList.size(); i++) {
System.out.println("intList.get("+i+")="+intList.get(i));
}
Collections.sort(intList, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return (o1>o2)?0:-1;
}
});
System.out.println("after sort");
for (int i=0; i<intList.size(); i++) {
System.out.println("intList.get("+i+")="+intList.get(i));
}
}
下面是示例代码的运行结果:
before sort
strArray[0]=abc
strArray[1]=aaa
strArray[2]=abb
strArray[3]=tgy
strArray[4]=ctr
after sort
strArray[0]=aaa
strArray[1]=abb
strArray[2]=abc
strArray[3]=ctr
strArray[4]=tgy
before sort
intList.get(0)=10
intList.get(1)=4
intList.get(2)=7
intList.get(3)=1
intList.get(4)=3
after sort
intList.get(0)=1
intList.get(1)=3
intList.get(2)=4
intList.get(3)=7
intList.get(4)=10
与排序算法相类似的,还有图片缓存用到的排队算法(又称淘汰算法、置换算法),例如:先进先出FIFO、后进先出LIFO、最近最久未使用LRU、最不经常使用LFU等等。有关图片缓存的介绍参见《 Android开发笔记(七十七)图片缓存算法》。
字符串显示策略
可变字符串SpannableString在显示不同文字样式上,便运用了策略模式,具体做法是调用setSpan函数设置指定范围文字的样式,然后在TextView显示文本时根据字符串显示策略分别予以展示相应样式。有关可变字符串的介绍参见《 Android开发笔记(六)可变字符串》,下面是对可变字符串分段设置显示策略的代码例子:
String str_url = "Let's go.";
String itemText = "Hello world. " + str_url;
SpannableString spanText = new SpannableString(itemText);
int first_length = 5;
int second_length = 12;
spanText.setSpan(new RelativeSizeSpan(1.5f) , 0, first_length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
spanText.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), 0, first_length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
spanText.setSpan(new RelativeSizeSpan(0.75f), first_length+1, second_length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
spanText.setSpan(new ForegroundColorSpan(Color.RED), first_length+1, second_length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
Spannable sp = (Spannable) Html.fromHtml("<a href=\"\">"+str_url+"</a>");
CharSequence text = sp.toString();
URLSpan[] urls = sp.getSpans(0, text.length(), URLSpan.class);
for (URLSpan url : urls) {
MyURLSpan myURLSpan = new MyURLSpan(url.getURL());
spanText.setSpan(myURLSpan, second_length+1, itemText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
tv_hello.setText(spanText);
下面是几个常见的字符串显示策略:
RelativeSizeSpan : 文字相对大小
AbsoluteSizeSpan : 文字绝对大小
ForegroundColorSpan : 文字前景色
BackgroundColorSpan : 文字背景色
StyleSpan : 文字风格(正常、粗体、斜体)
TypefaceSpan : 字体
ImageSpan : 图文混排
URLSpan : 超链接样式
动画插值器和估值器
Android计算动画过程中的变化值,可采用不同的插值器算法,以实现动画变化的速率快慢;另外,插值器计算得到的只是一个默认的起始值与终止值,如果我们想将其转变为自定义的起始与终止效果,还得应用估值器算法。有关动画以及插值器和估值器的介绍参见《Android开发笔记(九十六)集合动画与属性动画》,下面是对属性动画运用插值器和估值器算法的代码例子:
// 插值器和估值器
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
private void animatorValue() {
ObjectAnimator anim1 = ObjectAnimator.ofInt(tv_object_text, "backgroundColor", 0xFFFF0000, 0xFFFFFFFF);
anim1.setInterpolator(new AccelerateInterpolator());
anim1.setEvaluator(new ArgbEvaluator());
ObjectAnimator anim2 = ObjectAnimator.ofFloat(tv_object_text, "rotation", 0f, 360f);
anim2.setInterpolator(new DecelerateInterpolator());
anim2.setEvaluator(new FloatEvaluator());
ObjectAnimator anim3 = ObjectAnimator.ofObject(tv_object_text, "clipBounds", new RectEvaluator(), new Rect(0,0,250,100), new Rect(0,0,100,50), new Rect(0,0,250,100));
anim3.setInterpolator(new LinearInterpolator());
ObjectAnimator anim4 = ObjectAnimator.ofInt(tv_object_text, "textColor", 0xFF000000, 0xFF0000FF);
anim4.setInterpolator(new BounceInterpolator());
anim4.setEvaluator(new IntEvaluator());
AnimatorSet animSet = new AnimatorSet();
AnimatorSet.Builder builder = animSet.play(anim1);
builder.with(anim2).after(anim3).before(anim4);// anim3先执行,然后再同步执行anim1、anim2,最后执行anim4
animSet.setDuration(6000);
animSet.start();
}
点此查看Android开发笔记的完整目录