设计模式之模板方法浅析
/** * * 设计原则: * 好莱坞原则:别调用我,我会调用你 * 好莱坞法则的目的在于:防止依赖腐败 让高层组件调用底层组件 * * 模板方法模式: 定义了一个算法的框架,允许子类为其提供一个或多个步骤的实现 * 模板方法和策略方法都封装算法,模板使用继承,策略使用组合 * 工厂方法为模板方法的特例 * * 钩子: * 被声明在抽象类中的方法,但是有默认的或者空的实现,给子类决定要不要重写 * 让子类决定算法中的某些部分是否需要 * * 示例: 咖啡和茶的冲泡过程 * 咖啡:把水煮开、用沸水冲泡咖啡、把咖啡倒进杯子、加糖和牛奶 * 茶叶:把水煮开、用沸水浸泡茶叶、把茶倒进杯子、加柠檬 * * @author Administrator * */
模板方法示例采用咖啡和茶叶的冲泡流程
咖啡和茶叶都含有咖啡因 都称为咖啡因饮料
package com.undergrowth.template; /** * * 设计原则: * 好莱坞原则:别调用我,我会调用你 * 好莱坞法则的目的在于:防止依赖腐败 让高层组件调用底层组件 * * 模板方法模式: 定义了一个算法的框架,允许子类为其提供一个或多个步骤的实现 * 模板方法和策略方法都封装算法,模板使用继承,策略使用组合 * 工厂方法为模板方法的特例 * * 钩子: * 被声明在抽象类中的方法,但是有默认的或者空的实现,给子类决定要不要重写 * 让子类决定算法中的某些部分是否需要 * * 示例: 咖啡和茶的冲泡过程 * 咖啡:把水煮开、用沸水冲泡咖啡、把咖啡倒进杯子、加糖和牛奶 * 茶叶:把水煮开、用沸水浸泡茶叶、把茶倒进杯子、加柠檬 * * @author Administrator * */ public abstract class CaffeineBeverage { /** * 茶和咖啡的冲泡算法 模板方法声明为final 不允许子类重写 */ public final void prepareRecipe() { boilWater(); brew(); pourInCup(); //加上钩子 控制步骤 if(isAddCondiment()){ addCondiments(); } } /** * 钩子方法 * @return */ boolean isAddCondiment() { // TODO Auto-generated method stub return true; } /** * 相同步骤 */ void boilWater() { System.out.println("把水煮开"); } /** * 冲泡方式不一样 留给子类实现 */ abstract void brew(); void pourInCup() { // TODO Auto-generated method stub System.out.println("把饮料倒进杯子"); } /** * 加调料不一样 留给子类实现 */ abstract void addCondiments(); }
咖啡
package com.undergrowth.template; public class Coffee extends CaffeineBeverage { @Override void brew() { // TODO Auto-generated method stub System.out.println("用沸水冲泡咖啡"); } @Override void addCondiments() { // TODO Auto-generated method stub System.out.println("加糖和牛奶"); } }
茶
package com.undergrowth.template; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; public class Tea extends CaffeineBeverage { @Override void brew() { // TODO Auto-generated method stub System.out.println("用沸水浸泡茶叶"); } @Override void addCondiments() { // TODO Auto-generated method stub System.out.println("加柠檬"); } /** * 重写钩子方法 */ @Override boolean isAddCondiment() { // TODO Auto-generated method stub boolean isAdd=true; String input=getInput(); if(!"y".equalsIgnoreCase(input)){ isAdd=false; } return isAdd; } private String getInput() { // TODO Auto-generated method stub String input=null; System.out.println("是否想要在茶中添加饮料"); BufferedReader reader=new BufferedReader(new InputStreamReader(System.in)); try { input=reader.readLine(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return input; } }
测试
package com.undergrowth.template.test; import static org.junit.Assert.*; import org.junit.Test; import com.undergrowth.template.CaffeineBeverage; import com.undergrowth.template.Coffee; import com.undergrowth.template.Tea; public class CaffeineBeverageTest { @Test public void test() { CaffeineBeverage baBeverage=new Tea(); System.out.println("开始泡茶"); baBeverage.prepareRecipe(); baBeverage=new Coffee(); System.out.println("==================开始冲泡咖啡=================="); baBeverage.prepareRecipe(); } }
控制台输出
开始泡茶 把水煮开 用沸水浸泡茶叶 把饮料倒进杯子 是否想要在茶中添加饮料 Y 加柠檬 ==================开始冲泡咖啡================== 把水煮开 用沸水冲泡咖啡 把饮料倒进杯子 加糖和牛奶
再来看看模板方法的一个变体的应用
Arrays.sort()方法 比较鸭子的体重 然后进行排序
package com.undergrowth.template; /** * 鸭子比较器 * @author Administrator * */ public class DuckComparable implements Comparable<Object> { int weight; String name; public DuckComparable(int weight, String name) { super(); this.weight = weight; this.name = name; } /** * 比较两个鸭子的体重 是否相等 */ @Override public int compareTo(Object o) { // TODO Auto-generated method stub DuckComparable otherDuckComparable=(DuckComparable) o; if(this.weight>otherDuckComparable.weight) return 1; else if(this.weight==otherDuckComparable.weight) return 0; else { return -1; } } @Override public String toString() { return "DuckComparable [weight=" + weight + ", name=" + name + "]"; } }
测试
package com.undergrowth.template.test; import static org.junit.Assert.*; import java.util.Arrays; import org.junit.Test; import com.undergrowth.template.DuckComparable; public class DuckComparableTest { @Test public void test() { DuckComparable[] ducks = { new DuckComparable(100, "绿头鸭"), new DuckComparable(85, "红头鸭"), new DuckComparable(110, "黑头鸭") , new DuckComparable(57, "蓝头鸭")}; System.out.println("===================未排序的鸭子==================="); display(ducks); System.out.println("===================已排序的鸭子==================="); Arrays.sort(ducks); display(ducks); } private void display(DuckComparable[] ducks) { // TODO Auto-generated method stub for (int i = 0; i < ducks.length; i++) { System.out.println(ducks[i]); } } }
控制台
===================未排序的鸭子=================== DuckComparable [weight=100, name=绿头鸭] DuckComparable [weight=85, name=红头鸭] DuckComparable [weight=110, name=黑头鸭] DuckComparable [weight=57, name=蓝头鸭] ===================已排序的鸭子=================== DuckComparable [weight=57, name=蓝头鸭] DuckComparable [weight=85, name=红头鸭] DuckComparable [weight=100, name=绿头鸭] DuckComparable [weight=110, name=黑头鸭]
现在再来追踪看下 Arrays.sort方法 是如何实现的
/** * Sorts the specified array of objects into ascending order, according * to the {@linkplain Comparable natural ordering} of its elements. * All elements in the array must implement the {@link Comparable} * interface. Furthermore, all elements in the array must be * <i>mutually comparable</i> (that is, {@code e1.compareTo(e2)} must * not throw a {@code ClassCastException} for any elements {@code e1} * and {@code e2} in the array). *
public static void sort(Object[] a) { if (LegacyMergeSort.userRequested) legacyMergeSort(a); else ComparableTimSort.sort(a); }上面是说以升序的方式进行排序 并且数组中的每个元素必须要实现Comparable接口
往下看 ComparableTimSort类的
/* * The next two methods (which are package private and static) constitute * the entire API of this class. Each of these methods obeys the contract * of the public method with the same signature in java.util.Arrays. */ static void sort(Object[] a) { sort(a, 0, a.length); }
static void sort(Object[] a, int lo, int hi) { rangeCheck(a.length, lo, hi); int nRemaining = hi - lo; if (nRemaining < 2) return; // Arrays of size 0 and 1 are always sorted // If array is small, do a "mini-TimSort" with no merges if (nRemaining < MIN_MERGE) { int initRunLen = countRunAndMakeAscending(a, lo, hi); binarySort(a, lo, hi, lo + initRunLen); return; } /** * March over the array once, left to right, finding natural runs, * extending short natural runs to minRun elements, and merging runs * to maintain stack invariant. */ ComparableTimSort ts = new ComparableTimSort(a); int minRun = minRunLength(nRemaining); do { // Identify next run int runLen = countRunAndMakeAscending(a, lo, hi); // If run is short, extend to min(minRun, nRemaining) if (runLen < minRun) { int force = nRemaining <= minRun ? nRemaining : minRun; binarySort(a, lo, lo + force, lo + runLen); runLen = force; } // Push run onto pending-run stack, and maybe merge ts.pushRun(lo, runLen); ts.mergeCollapse(); // Advance to find next run lo += runLen; nRemaining -= runLen; } while (nRemaining != 0); // Merge all remaining runs to complete sort assert lo == hi; ts.mergeForceCollapse(); assert ts.stackSize == 1; }
看到binarySort方法
private static void binarySort(Object[] a, int lo, int hi, int start) { assert lo <= start && start <= hi; if (start == lo) start++; for ( ; start < hi; start++) { @SuppressWarnings("unchecked") Comparable<Object> pivot = (Comparable) a[start]; // Set left (and right) to the index where a[start] (pivot) belongs int left = lo; int right = start; assert left <= right; /* * Invariants: * pivot >= all in [lo, left). * pivot < all in [right, start). */ while (left < right) { int mid = (left + right) >>> 1; if (pivot.compareTo(a[mid]) < 0) right = mid; else left = mid + 1; } assert left == right; /* * The invariants still hold: pivot >= all in [lo, left) and * pivot < all in [left, start), so pivot belongs at left. Note * that if there are elements equal to pivot, left points to the * first slot after them -- that's why this sort is stable. * Slide elements over to make room for pivot. */ int n = start - left; // The number of elements to move // Switch is just an optimization for arraycopy in default case switch (n) { case 2: a[left + 2] = a[left + 1]; case 1: a[left + 1] = a[left]; break; default: System.arraycopy(a, left, a, left + 1, n); } a[left] = pivot; } }
这里的
if (pivot.compareTo(a[mid]) < 0)即使调用实现Comparable接口的compareTo方法 进行比较
posted on 2014-12-15 22:37 liangxinzhi 阅读(134) 评论(0) 编辑 收藏 举报