设计模式13-- 模板模式怎么弄()

愿君学长松,慎勿作桃李。这篇文章主要讲述设计模式13-- 模板模式怎么弄?相关的知识,希望能为你提供帮助。
开局还是那种图,各位客官往下看...

张无忌学太极拳,忘记了所有招式,打倒了"玄冥二老",所谓"心中无招"。设计模式可谓招数,如果先学通了各种模式,又忘掉了所有模式而随心所欲,可谓OO之最高境界。
模板模式是什么?模板模式,同样是一种行为型模式,也就是关于对象做什么或者怎么做的设计模式。模板模式的本质需要定义操作中的算法的框架,但是有一些步骤,又不需要具体的实现,而是不同的子类各自实现。子类不能修改流程框架,但是部分的步骤可以做定制化的实现。
主要要解决一个问题:一些通用的方法,但是每一个子类却都重新写,冗余。
比如说,做菜的步骤一般是:洗锅 --> 炒菜 --> 洗碗 ,不同的菜,只是炒菜这一个步骤具体细节是不同的,但是其他步骤确实几乎一模一样的,这样其实整体框架,以及重复的步骤,我们可以抽象到模板中,而不同的细节方法可以开放给每一种菜(具体实现)去定制。
又比如造房子的时候,很多地方的建造都是一样的:地基,墙壁,水管等等,但是不同的房子里面的内部的设计又有所不同。
不使用模板模式就挑个简单的例子“炒菜”,如果不使用模板模式的话,糖醋鲤鱼:
public class SweetAndSourCarp

public void cookFood()
washPan();
cook();
eat();
washDishes();
System.out.println("");


private void washPan()
System.out.print("洗锅 --> ");


private void cook()
System.out.print("煮糖醋鲤鱼 --> ");


private void eat()
System.out.print("吃饭 --> ");


private void washDishes()
System.out.print("洗碗 --> ");


再弄一个农家小炒肉,需要写很多相同的方法:
public class ShreddedPorkWithVegetables

public void cookFood()
washPan();
cook();
eat();
washDishes();
System.out.println("");


private void washPan()
System.out.print("洗锅 --> ");


private void cook()
System.out.print("炒农家小炒肉 --> ");


private void eat()
System.out.print("吃饭 --> ");


private void washDishes()
System.out.print("洗碗 --> ");


测试类如下:
public class Test
public static void main(String[] args)
SweetAndSourCarp sweetAndSourCarp = new SweetAndSourCarp();
sweetAndSourCarp.cookFood();

ShreddedPorkWithVegetables shreddedPorkWithVegetables = new ShreddedPorkWithVegetables();
shreddedPorkWithVegetables.cookFood();


测试结果:
洗锅 --> 煮糖醋鲤鱼 --> 吃饭 --> 洗碗 -->
洗锅 --> 炒农家小炒肉 --> 吃饭 --> 洗碗 -->

可以看到,整体流程是一样的,有些步骤一样,有些步骤不一样,但是不使用模板模式,需要每个类都重写一遍方法,即使是通用方法,整个流程都需要自己写一遍。
使用模板模式优化如果使用模板模式,那么我们会抽象出一个抽象类,定义整体的流程,已经固定的步骤,开放需要定制的方法,让具体的实现类按照自己的需求来定制。

定义的抽象类:
public abstract class CookFood
public final void cookFood()
washPan();
cook();
eat();
washDishes();
System.out.println("");


private final void washPan()
System.out.print("洗锅 --> ");


public abstract void cook();

private final void eat()
System.out.print("吃饭 --> ");


private final void washDishes()
System.out.print("洗碗 --> ");


具体的实现类糖醋鲤鱼:
public class SweetAndSourCarp extends CookFood
@Override
public void cook()
System.out.print("煮糖醋鲤鱼 --> ");


农家小炒肉:
public class ShreddedPorkWithVegetables extends CookFood
@Override
public void cook()
System.out.print("炒农家小炒肉 --> ");


测试类与前面的一样,测试结果也一样,这里不再重复。
上面的方法中,其实我们只开放了cook()方法,这就是钩子方法:
在模板方法模式的父类中,我们可以定义一个方法,它默认不做任何事,子类可以视情况要不要覆盖它,该方法称为 ”钩子方法”
【设计模式13-- 模板模式怎么弄()】钩子方法是开放的,可以由子类随意覆盖,但是像上面的其他方法,我们不希望子类重写或者覆盖它,就可以用 final 关键字,防止子类重写模板方法。
模板模式的应用其实在 JDKThread 实现中,就是使用了模板模式,我们知道创建线程有两个方式:
  • 创建 Thread
  • 实现 runnable 接口
我们实现的一般是 run() 方法, 但是调用的却是 start() 方法来启动线程,这个原因就是 start() 方法里面帮我们调用了run() 方法, run()方法是开发的方法,我们可以覆盖重写它。

Start0()是一个native方法,是由 c 语言去实现的,在调用的时候,真正调用了我们的 run() 方法,如果需要跟踪这个方法需要到 HotSpot底层去。这里介绍的目的是让大家了解,它同样是使用了模板模式。
private native void start0();

了解 native 关键字可以参考:http://aphysia.cn/archives/native
模板模式的优缺点模板模式的优点:
  • 1、封装固定的部分,拓展需要定制修改的部分,符合开闭原则。
  • 2、公共的代码在父类中,容易维护。
  • 3、整个流程由父类把握,调整比较方便。
缺点:


  • 1、子类可能会很多,系统复杂度上升。
  • 2、子类只有一小部分实现,了解全部方法则需要在父类中阅读,影响代码阅读。
总结:代码该隐藏的复杂细节隐藏起来,开放定制化部分,优雅!
设计模式系列:
  • 设计模式【1】-- 单例模式到底几种写法?
  • 设计模式【1.1】-- 你想如何破坏单例模式?
  • 设计模式【1.2】-- 枚举式单例有那么好用么?
  • 设计模式【1.3】-- 为什么饿汉式单例是线程安全的?
  • 设计模式【2】-- 简单工厂模式了解一下?
  • 设计模式【2.1】-- 简单工厂模式怎么演变成工厂方法模式?
  • 设计模式【2.2】-- 工厂模式怎么演变成抽象工厂模式?
  • 设计模式【3.1】-- 浅谈代理模式之静态、动态、cglib代理
  • 设计模式【3.2】-- JDK动态代理源码分析有多香?
  • 设计模式【3.3】-- CGLIB动态代理源码解读
  • 设计模式【4】-- 建造者模式详解
  • 设计模式【5】-- 原型模式
  • 设计模式【6.1】-- 初探适配器模式
  • 设计模式【6.2】-- 再聊聊适配器模式
  • 设计模式【7】-- 探索一下桥接模式
  • 设计模式【8】-- 手工耿教我写装饰器模式
  • 设计模式【9】-- 外观模式?没那么高大上
  • 设计模式【10】-- 顺便看看享元模式
  • 设计模式【11】-- 搞定组合模式
  • 设计模式【12】-- 搞定最近大火的策略模式
【作者简介】:
秦怀,公众号【秦怀杂货店】作者,个人网站:http://aphysia.cn,技术之路不在一时,山高水长,纵使缓慢,驰而不息。
剑指Offer全部题解PDF
??开源编程笔记??


    推荐阅读