• 《Head First 设计模式》学习笔记——模板方法模式


    模板方法模式是类的行为模式。准备一个抽象类,将部分逻辑以详细方法以及详细构造函数的形式实现。然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类能够以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。这就是模板方法模式的用意。

    设计模式
    模板方法模式:在一个方法中定义一个算法的框架,而将一些步骤延迟到子类中。模板方法使得子类能够在不改变算法结果的情况下,又一次定义算法中的某些步骤。

    模板就是一个方法。这种方法将算法定义成一组步骤。当中的不论什么步骤都能够是抽象的,由子类负责实现。这样能够确保算法的结构保持不变。同一时候由子类提供部分实现。


    钩子是一种被声明在抽象类中的方法,但仅仅有空或默认的实现,钩子的存在,能够让子类有能力对算法的不同点进行挂钩。要不要挂钩,有子类自行决定。

    使用钩子的真正目的:
    钩子能够让子类实现算法中可选的部分,或者在钩子对于子类的实现并不重要的时候,子类能够对此钩子置之不理。

    钩子的还有一个使用方法,是让子类能够有机会对模板方法中某些即将发生的(或刚刚发生的)步骤做出反应。


    设计原则
    好莱坞原则:别调用我们,我们会调用你。
    在好莱坞原则下,我们同意低层组件将自己挂钩到系统之上。可是高层组件会决定什么时候和如何使用这些低层组件。换句话说,高层组件对低层组件的方式是“别调用我们,我们会调用你”。

    要点
    “模板方法”定义了算法的步骤,把这些步骤的实现延迟到子类中。

    模板方法模式为我们提供了一种代码复用的重要技巧。

    模板方法的抽象类能够定义详细方法、抽象方法、钩子。
    为了防止子类改变模板方法中的算法,我们能够将模板方法声明为final。
    策略模式和模板方法模式都是封装算法,前者是使用组合。后者是使用继承。
    工厂方法是模板方式的一种特殊版本号。


    典型的摸板方法应用
    1. HttpServlet技术
    2. Swing的窗体程序
    3. Applet

    模板方法模式:
    //声明为抽象类,子类必须实现其操作
    public abstract class CaffeineBeverage
    {
    
    	//声明为final,不希望子类覆盖这种方法
    	final void prepareRecipe()
    	{
    		boilWater();
    		brew();
    		pourInCup();
    		addCondiments();
    	}
    
    	//声明为抽象类,子类必须实现其操作
    	abstract void brew();
    	abstract void addCondiments();
    
    	void boilWater()
    	{
    		System.out.println("Boiling water");
    	}
    
    	void pourInCup()
    	{
    		System.out.println("Pouring into cup");
    	}
    }
    
    //extends继承
    public class Tea extends CaffeineBeverage {
    	//须要定义抽象方法
    	public void brew() {
    		System.out.println("Steeping the tea");
    	}
    	public void addCondiments() {
    		System.out.println("Adding Lemon");
    	}
    }
    

    使用钩子:
    public abstract class CaffeineBeverageWithHook {
     
    	void prepareRecipe() {
    		boilWater();
    		brew();
    		pourInCup();
    		if (customerWantsCondiments()) {
    			addCondiments();
    		}
    	}
     
    	abstract void brew();
     
    	abstract void addCondiments();
     
    	void boilWater() {
    		System.out.println("Boiling water");
    	}
     
    	void pourInCup() {
    		System.out.println("Pouring into cup");
    	}
     
    	//定义了一个缺省实现,子类能够覆盖它。但不见得一定要这么做
    	boolean customerWantsCondiments() {
    		return true;
    	}
    }
    
    public class CoffeeWithHook extends CaffeineBeverageWithHook {
     
    	public void brew() {
    		System.out.println("Dripping Coffee through filter");
    	}
     
    	public void addCondiments() {
    		System.out.println("Adding Sugar and Milk");
    	}
     
    	//覆盖了这种方法。提供了自己的功能
    	public boolean customerWantsCondiments() {
    
    		//让用户输入对调料的决定
    		String answer = getUserInput();
    
    		if (answer.toLowerCase().startsWith("y")) {
    			return true;
    		} else {
    			return false;
    		}
    	}
     
    	private String getUserInput() {
    		String answer = null;
    
    		System.out.print("Would you like milk and sugar with your coffee (y/n)? ");
    
    		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
    		try {
    			answer = in.readLine();
    		} catch (IOException ioe) {
    			System.err.println("IO error trying to read your answer");
    		}
    		if (answer == null) {
    			return "no";
    		}
    		return answer;
    	}
    }


  • 相关阅读:
    【转】周杰伦在哪几届金曲奖中分别得的哪些奖?
    【转】Linux shell的&&和||
    【转】Ubuntu13.04配置:Vim+Syntastic+Vundle+YouCompleteMe
    【转】Notepad++中Windows,Unix,Mac三种格式之间的转换
    【转】vim环境设置和自动对齐
    【转】Vim自动补全插件----YouCompleteMe安装与配置
    【转】foxmail邮箱我已进清理了为什么还是说我的邮箱已满
    强化学习
    奇人有奇书(李渔、张岱、陈继儒、吴敬梓)
    奇人有奇书(李渔、张岱、陈继儒、吴敬梓)
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/5177887.html
Copyright © 2020-2023  润新知