建站时长是什么原因造成的,wordpress 3.0.1,宝贝做网站,吴谨含厂家不愿做网站“项目评审的节点又快到了#xff0c;PPT你写了没#xff1f;” “Oops#xff0c;忘了#xff0c;有模板没#xff1f;给我一份” 概述
模板#xff0c;一个频繁出现在办公室各类角色口中的词#xff0c;它通常意味着统一、高效、经验和优质。各项汇报因为PPT的模板变… “项目评审的节点又快到了PPT你写了没” “Oops忘了有模板没给我一份” 概述
模板一个频繁出现在办公室各类角色口中的词它通常意味着统一、高效、经验和优质。各项汇报因为PPT的模板变得更加生动各式的报告因为有了文档模板变得更加规范。找规律是人类很愿意钻研的工作之一那么在设计模式中是否有一种模板能够帮我们解决一些问题呢 答案是肯定的有 一言
模板方法模式定义一个操作中的算法的骨架将一些步骤延迟到子类中使得子类可以不改变一个算法的结构就可以重新定义该算法的某些特定步骤。 炼金术 为了更好的理解模板模式我想起了这样一个场景。我们都玩过打怪升级的养成类游戏拿到了野外的原料再去城里的铁匠铺锻造不同的材料会合成不同的装备。 如果让你用代码实现这个需求你有什么样的思路 我们只要稍加思索就会发现这个需求中大部分的过程都是不变的唯一的变数就在于投入的原料在这样的场景下模板方法模式就非常契合我们的需求了。 原理 AbstractClass抽象类类中实现了模板方法定义了算法骨架具体子类需要实现其它抽象方法operation2,3,4ConcreteClass实现抽象方法operation2,3,4,以完成算法中特定子类的步骤
简单实现
铁匠铺
public abstract class BlackSmith {final void make(){fire();putMaterial();hit();}void fire(){System.out.println(锻造炉升温);}abstract void putMaterial();void hit(){System.out.println(开始制作);}
}铸剑室
public class SwordBlackSmith extends BlackSmith{Overridevoid putMaterial() {System.out.println(放入铸剑材料铁矿石);}
}制弓室
public class ArchBlackSmith extends BlackSmith{Overridevoid putMaterial() {System.out.println(放入制弓材料木材牛筋);}
}钩子方法
上面的实现通俗易懂下面我们思考一下模板方法中如果我需要视情况规避掉其中几个方法的执行应该如何实现 比如说”冬天到了铁匠铺没有生意但是铁匠很冷他只想让锻造炉升温但是不需要放入任何锻造材料“。你有什么思路 实际上这种需求就可以用钩子方法来实现下面我们在原来的实现上稍加处理。 铁匠铺含钩子
public abstract class BlackSmith {final void make(){fire();if (work()){putMaterial();hit();}}void fire(){System.out.println(锻造炉升温);}abstract void putMaterial();void hit(){System.out.println(开始制作);}boolean work(){return true;}
}凛冬将至
public class WinterIsComing extends BlackSmith{Overridevoid putMaterial() {}Overrideboolean work() {return false;}
}IOC源码中模板方法模式的应用
相信刷过Java八股的同学在刚刚读到钩子方法的时候就已经想到了IOC容器初始化的实现了各种论坛、文档上只要一提IOC过程、容器初始化 必然会说到钩子方法但是相信很多同学也和笔者起初一样对这种生涩的描述感觉一头雾水。今天我就带大家把这个听起来很晦涩的描述讲通。 没错作为设计模式的集大成者springframework在IOC的源码实现中包含着大量的钩子函数实现这里也是对模板方法模式的主要应用。 我们先来看框架结构 spring源码中上下文接口ApplicationContext是很靠近底层的一个接口它也是很重要的一个衔接接口。ConfigurableApplicationContext接口作为ApplicaitonContext的一个分支实现承担了大量的springIOC初始化工作而ConfigurableApplicationContext有一个核心的实现类AbstractApplicationContext在这个实现类中有一个很重要很重要很重要的方法就是refresh()方法。 我愿意称这个方法为spring之梦开始的地方这个方法就是模板方法模式的典型应用包含了各种前置后置实现和钩子方法更是spring生命周期的核心体现。 相关源码 Overridepublic void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {StartupStep contextRefresh this.applicationStartup.start(spring.context.refresh);// Prepare this context for refreshing.prepareRefresh();// Tell the subclass to refresh the internal bean factory.ConfigurableListableBeanFactory beanFactory obtainFreshBeanFactory();// Prepare the bean factory for use in this context.prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.postProcessBeanFactory(beanFactory);StartupStep beanPostProcess this.applicationStartup.start(spring.context.beans.post-process);// Invoke factory processors registered as beans in the context.invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.registerBeanPostProcessors(beanFactory);beanPostProcess.end();// Initialize message source for this context.initMessageSource();// Initialize event multicaster for this context.initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses.onRefresh();// Check for listener beans and register them.registerListeners();// Instantiate all remaining (non-lazy-init) singletons.finishBeanFactoryInitialization(beanFactory);// Last step: publish corresponding event.finishRefresh();}catch (BeansException ex) {if (logger.isWarnEnabled()) {logger.warn(Exception encountered during context initialization - cancelling refresh attempt: ex);}// Destroy already created singletons to avoid dangling resources.destroyBeans();// Reset active flag.cancelRefresh(ex);// Propagate exception to caller.throw ex;}finally {// Reset common introspection caches in Springs core, since we// might not ever need metadata for singleton beans anymore...resetCommonCaches();contextRefresh.end();}}}在这个方法中postProcessBeanFactoryonRefresh都是预留的钩子方法在这里都是空实现。而对于这些钩子的实现往往依赖于更高层的子类比如说GenericWebApplicationContext。 相关源码 /*** Modify the application contexts internal bean factory after its standard* initialization. All bean definitions will have been loaded, but no beans* will have been instantiated yet. This allows for registering special* BeanPostProcessors etc in certain ApplicationContext implementations.* param beanFactory the bean factory used by the application context*/protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {}/*** Template method which can be overridden to add context-specific refresh work.* Called on initialization of special beans, before instantiation of singletons.* pThis implementation is empty.* throws BeansException in case of errors* see #refresh()*/protected void onRefresh() throws BeansException {// For subclasses: do nothing by default.}/*** Register request/session scopes, environment beans, a {link ServletContextAwareProcessor}, etc.*/Overrideprotected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {if (this.servletContext ! null) {beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext));beanFactory.ignoreDependencyInterface(ServletContextAware.class);}WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext);}//.../*** Initialize the theme capability.*/Overrideprotected void onRefresh() {this.themeSource UiApplicationContextUtils.initThemeSource(this);}GenericWebApplicationContext对两个钩子写了具体的实现并根据自己的需求在refresh时按部就班的触发形成了类似子——父——子的调用关系这就是模板方法模式的魅力所在。 怎么样相信大家看到这里会发现其实源码并没有那么晦涩一些听到就打怵的词汇也没有那么高深。感兴趣的同学可以根据我的描述自己再追溯一下上述源码深度理解下。 结
模板方法模式的基本思想其实还是想让算法只存在于一处这样更方便修改。本质上还是为了实现最大化的代码复用。就像我们开始说的PPT模板一样父类模板方法实现的某些步骤可以直接被子类拿来使用。 这样既统一了算法也提供了很大的灵活性。父类模板结构稳定子类实现花样百出。 不过这种设计模式也存在着短板就是可能引发类爆炸的问题每一个不同的实现都需要一个子类系统会逐渐变得笨重。所以一般模板方法都会加上final防止子类重写模板方法。 关注我共同进步每天进步一点点。——Wayne