zoukankan      html  css  js  c++  java
  • 设计模式之模板方法浅析

    /**
     * 
     * 设计原则:
     *   好莱坞原则:别调用我,我会调用你
     *   好莱坞法则的目的在于:防止依赖腐败  让高层组件调用底层组件
     *   
     * 模板方法模式: 定义了一个算法的框架,允许子类为其提供一个或多个步骤的实现
     *   模板方法和策略方法都封装算法,模板使用继承,策略使用组合
     *   工厂方法为模板方法的特例
     * 
     * 钩子:
     *   被声明在抽象类中的方法,但是有默认的或者空的实现,给子类决定要不要重写
     *   让子类决定算法中的某些部分是否需要
     * 
     * 示例: 咖啡和茶的冲泡过程 
     * 咖啡:把水煮开、用沸水冲泡咖啡、把咖啡倒进杯子、加糖和牛奶 
     * 茶叶:把水煮开、用沸水浸泡茶叶、把茶倒进杯子、加柠檬
     * 
     * @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方法 进行比较

  • 相关阅读:
    python学习之控制语句
    linux中的网络基础
    python学习之准备
    linux用户权限
    python学习之函数和函数参数
    python学习之输出与文件读写
    linux中的vim编辑器的使用
    从产品和用户角度,思考需求和用户体验
    好记性不如烂笔头
    TI DaVinci(达芬奇)入门
  • 原文地址:https://www.cnblogs.com/liangxinzhi/p/4275540.html
Copyright © 2011-2022 走看看