设计模式之模板模式
- 模板模式总结
- 泡茶和泡咖啡的案例
- 传统设计
- 模板方法设计
- Sort排序算法应用模板方法设计模式
- 好莱坞原则
模板模式总结
- 封装了一个算法步骤,并允许子类为一个或多个步骤方法提供实现,模板模式可以使得子类在不改变算法结构的情况下,重新定义算法中的某些实现;
- 在模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行;
- 应用: 1、在造房子的时候,地基、走线、水管都一样,只有在建筑的后期才有加壁橱加栅栏等差异。 2、西游记里面菩萨定好的 81 难,这就是一个顶层的逻辑骨架。 3、spring 中对 Hibernate 的支持,将一些已经定好的方法封装起来,比如开启事务、获取 Session、关闭 Session 等,程序员不重复写那些已经规范好的代码,直接丢一个实体就可以保存。
- 优点:1、封装不变部分,扩展可变部分。 2、提取公共代码,便于维护。 3、行为由父类控制,子类实现。
- 使用场景 : 1、有多个子类共有的方法,且逻辑相同。 2、重要的、复杂的方法,可以考虑作为模板方法。
- 一般模板方法都加上 final 关键词。
泡茶和泡咖啡的案例
传统设计
package templateMethod.bad;
/**
* 泡咖啡的
*/
public class Coffee {
//步骤
public void prepareRecipe(){
boilWater();
brewCoffee();
pourInCup();
addSugarMilk();
}
public void boilWater(){
System.out.println("Boiling Water!");
}
public void brewCoffee(){
System.out.println("Brewing Coffee!");
}
public void pourInCup(){
System.out.println("Pouring into cup!");
}
public void addSugarMilk(){
System.out.println("Adding sugar and milk!");
}
}
package templateMethod.bad;
/**
* 泡热饮
*/
public class Tea {
public void prepareRecipe(){
boilWater();
brewTea();
pourInCup();
addLemon();
}
public void boilWater(){
System.out.println("Boiling Water!");
}
public void brewTea(){
System.out.println("Brewing Tea!");
}
public void pourInCup(){
System.out.println("Pouring into Cup!");
}
public void addLemon(){
System.out.println("Adding Lemon!");
}
}
package templateMethod.bad;
public class MyTest {
public static void main(String[] args) {
Coffee coffee = new Coffee();
Tea tes = new Tea();
coffee.prepareRecipe();
System.out.println("------------------");
tes.prepareRecipe();
}
}
模板方法设计
代码:
package templateMethod.good;
public abstract class HotDrink {
//模板方法
public final void prepareRecipe(){
boilWater();
brew();
pourInCup();
if(wantCondimentsHook()){
addCondiments();
}else{
System.out.println("No Condiments!");
}
}
//最终方法 不能修改的
public final void boilWater(){
System.out.println("Boiling Water!");
}
public final void pourInCup(){
System.out.println("Pouring into cup!");
}
//抽象方法,子类必须实现
public abstract void brew();
public abstract void addCondiments();
//钩子方法,hook 子类可以实现也可以不实现 父类已经先实现一下
public boolean wantCondimentsHook(){
return true;
}
}
package templateMethod.good;
/**
* 泡咖啡的
*/
public class Coffee extends HotDrink{
@Override
public void brew() {
System.out.println("Brewing Coffee!");
}
@Override
public void addCondiments() {
System.out.println("Adding sugar and milk!");
}
}
package templateMethod.good;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* 泡热饮
*/
public class Tea extends HotDrink{
@Override
public void brew() {
System.out.println("Brewing Tea!"); //个性化的
}
@Override
public void addCondiments() {
System.out.println("Adding Lemon!");
}
//重写钩子方法
@Override
public boolean wantCondimentsHook() {
System.out.println("Condiments, yes or no ? please input(y/n): ");
BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));
String result = "";
try {
result = cin.readLine();
} catch (IOException e) {
e.printStackTrace();
}
if(result.equals("n")) return false;
else return true;
}
}
测试类:
package templateMethod.good;
public class MyTest {
public static void main(String[] args) {
HotDrink coffee = new Coffee();
HotDrink tea = new Tea();
coffee.prepareRecipe();
System.out.println("----------------tea--(implements the hook method)--------------");
tea.prepareRecipe();
}
}
运行结果:
Sort排序算法应用模板方法设计模式
- 排序(sort)算法是模板模式的一个应用;
- 对象的排列方式并不是完全相同, 所以需要排序(sort)算法compareTo()可以按需要定制(子类去实现), 但排序方法的结构不变(模板方法);
- 需要实现(implement)接口Comparable, 并实现接口的方法public int compareTo(Object object), 才可以使用Arrays.sort()进行排序(定制);
package templateMethod.sort;
public class Duck implements Comparable<Duck> {
String name;
int weight;
public Duck(String name, int weight) {
this.name = name;
this.weight = weight;
}
public int compareTo(Duck o2) {
Duck otherDuck = o2;
if (this.weight < otherDuck.weight) {
return -1;
} else if (this.weight == otherDuck.weight) {
return 0;
} else { // this.weight > otherDuck.weight
return 1;
}
}
public String toString() {
return name + " weighs " + weight;
}
}
package templateMethod.sort;
import java.util.Arrays;
public class MyTest {
public static void main(String[] args) {
Duck[] ducks = {
new Duck("Daffy", 8),
new Duck("Dewey", 2),
new Duck("Howard", 7),
new Duck("Louie", 2),
new Duck("Donald", 10),
new Duck("Huey", 2)
};
System.out.println("Before sorting:");
display(ducks);
Arrays.sort(ducks);
System.out.println("\nAfter sorting:");
display(ducks);
}
public static void display(Duck[] ducks) {
for (Duck d : ducks) {
System.out.println(d);
}
}
}
好莱坞原则
- 子类相当于明星,你做好个性化的就好;
- 步骤之类的,让经纪人(父类(做过程))做;
- 好莱坞原则则是一种用在创建框架或组件上的一种技巧,好让底层组件能够被挂钩计算,而又不会让高层组件依赖底层组件,它是创建一个有弹性的设计,允许底层结构能够互相操作,而又防止太过于依赖。