zoukankan      html  css  js  c++  java
  • 设计模式之模板方法模式(一)

    学习了前面的朋友都知道,目前为止,我们的议题都是绕着封装转;我们已经封装了对象创建、方法调用、复杂接口、鸭子、比萨...那接下来呢

    我们将要深入封装算法块、好让子类可以在任何时候都可以将自己挂接进运算里。我们甚至会在这里学到一个受好莱坞影响而启发的设计原则。

    喝点咖啡或茶饮

    有些人喜欢喝咖啡,没有咖啡感觉生活索然无趣;有些人喜欢喝茶。那么,同样是茶饮,两者有没有什么共同或者是啥的?其实,两者的冲泡方式非常相似。比如

    1. 咖啡冲泡法
    • (1)把水煮沸
    • (2)用沸水冲泡咖啡
    • (3)把咖啡倒进杯子
    • (4)加糖和牛奶
    1. 茶饮冲泡法
    • (1)把水煮沸
    • (2)用沸水浸泡茶叶
    • (3)把茶倒进杯子
    • (4)加柠檬

    转换成咖啡和茶的代码如下:

    public class Coffee {
        void prepareRecipe() {
            boilWater();
            brewCoffeeGrinds();
            pourInCup();
            addSugarAndMilk();
        }
    
        public void boilWater() {
            System.out.println("Boling water");
        }
    
        public void brewCoffeeGrinds() {
            System.out.println("Dripping Coffee through filter");
        }
    
        public void pourInCup() {
            System.out.print("Pouring into cup");
        }
    
        public void addSugarAndMilk() {
            System.out.println("Adding Sugar and Milk");
        }
    }
    
    public class Tea {
        void prepareRecipe() {
            boilWater();
            steepTeaBag();
            pourInCup();
            addLemon();
        }
    
        public void boilWater() {
            System.out.println("Boiling water");
        }
    
        public void steepTeaBag() {
            System.out.println("Steeping the tea");
        }
    
        public void addLemon() {
            System.out.println("Adding Lemon");
        }
    
        public void pourInCup() {
            System.out.println("Pouring into cup");
        }
    }
    
    
    

    茶类也是类似的,所以就会出现代码又相通的地方,给我们的提示就是,第一版的设计类图可以是如下的方式:

    更进一步的设计

    所以,查看了以上的代码和类图,咖啡和茶还有什么其他的共同点呢?让我们先从冲泡法下手。

    1. 把水煮沸
    2. 用热水泡咖啡或茶
    3. 把饮料倒进杯子
    4. 在饮料内加入适当的调料

    可以看到,1和4已经被抽出来,放到了基类中。2和3并没有抽出来,但它们本质还是一样的,只是应用在不同的饮料上罢了。

    那么,我们有办法将prepareRecipe()也抽象化吗?是的,我们可以哦

    抽象prepareRecipe()

    1. 我们所遇到的第一个问题,就是咖啡使用brewCoffeeGrinds()和addSuagrAndMilk()方法,而茶使用steepTeaBag()和addLemon().

    我们发现,steep和brew都是泡的动作;addSugarAndMilk和addLemon都是加调料,所以分别把他们统一成brew()和addCondiments()进行

    1. 现在我们有了新的prepareRecipe()方法,但是需要让它能够符合代码。要想这么做,我们先从CaffeineBeveage(咖啡因饮料)超类开始
    public abstract  class CaffeineBeverage {
        final void prepareRecipe() {
    
        }
    
        abstract  void brew();
    
        abstract  void addCondiments();
    
        void boilWater() {
            System.out.println("Boiling water");
        }
    
        void pourInCup() {
            System.out.println("Pouring into cup");
        }
    }
    
    
    1. 最后我们需要处理咖啡和茶类了。这两个类现在都依赖超类(咖啡因饮料)来处理冲泡法,所以只需要自行处理冲泡和添加调料部分即可:
    public class Tea extends CaffeineBeverage {
    	public void brew() {
    		System.out.println("Steeping the tea");
    	}
    	public void addCondiments() {
    		System.out.println("Adding Lemon");
    	}
    }
    
    public class Coffee extends CaffeineBeverage {
    	public void brew() {
    		System.out.println("Dripping Coffee through filter");
    	}
    	public void addCondiments() {
    		System.out.println("Adding Sugar and Milk");
    	}
    }
    

    那么我们在这个过程中做了什么呢?小编用书中给出的形象化的图给大家解释下:

    认识模板方法

    其实,我们在这个过程中已经使用了我们要学习的模板方法,prepareRecipe()就是我们的模板方法。为什么呢?

    • 毕竟它是一个方法
    • 它用作一个算法的模板,在这个例子中,算法是用来制作咖啡和茶饮的

    模板方法定义了一个算法的步骤,并允许子类为一个或多个步骤提供实现

    让我们泡茶喝吧

    让我们逐步地泡茶、追踪这个模板方法是如何工作的。你会得知在算法内的某些方法,该模板方法控制了算法。它让子类能够提供某些步骤的实现

    1. 首先我们需要一个茶对象
    Tea myTea = new Tea();
    
    1. 然后我们调用这个模板方法
    myTea.prepareRecipe();
    
    1. 把水煮沸
    boilWater();
    
    这件事情是在超类中进行的
    
    1. 接下来我们需要泡茶,这件事情只有子类才能知道要怎么做
    brew();
    
    1. 现在把茶倒进杯子中;所有的饮料做法都一样,所以这件事情发生在超类中
    pourInCup();
    
    1. 最后,我们加进调料,由于调料是各个饮料独有的,所以 由子类来实现它
    addCondiments();
    

    经过上述的流程,我们就初步模板方法模式给学会了。在今天的篇尾,我们定义下这个模板方法模式:
    模板方法模式:在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。

    这个模式是有从来创建一个算法的模块。什么是模块?如你所见,模板就是一个方法。更具体地说,这个方法将算法定义成一组步骤,其中的任何步骤都可以是抽象的,由子类负责实现。这可以确保算法的结构保持不变,同时由子类提供部分实现。

    好啦,今天的学习就先到这里。今天只是初步学习了模板方法模式,接下来还会有更有料的方式,下次不见不散。

    爱生活,爱学习,爱感悟,爱挨踢

  • 相关阅读:
    2021NUAA暑假集训 Day3 题解
    2021NUAA暑假集训 Day2 题解
    2021NUAA暑期模拟赛部分题解
    CodeForces 1038D Slime
    UVA 11149 Power of Matrix
    UVA 10655 Contemplation! Algebra
    UVA 10689 Yet another Number Sequence
    HDU 4549 M斐波那契数列
    HDU 4990 Reading comprehension
    CodeForces 450B Jzzhu and Sequences
  • 原文地址:https://www.cnblogs.com/dimple91/p/10973159.html
Copyright © 2011-2022 走看看