設計模式--第12篇(模板方法模式)

一,模板方法模式

模板方法模式:

  1. 在一個抽象類中公開定義執行邏輯方法的模板,子類可以按照需要重寫方法實現,調用按照抽象類中定義的方法進行;
  2. 可以看做定義了一個算法的骨架,將一些步驟延遲到子類,使得子類中不需要改變算法的結構,就可以重定義該算法的某些特定功能;

二,原理類圖

在這裏插入圖片描述
意圖: 定義一個操作中的算法的骨架,而將一些步驟延遲到子類中。TemplateMethod 使得子類可以不改變一個算法的結構即可重定義該算法的某些特定步驟。
適用性: 一次性實現一個算法的不變的部分,並將可變的行爲留給子類來實現。各子類中公共的行爲應被提取出來並集中到一個公共父類中以避免代碼重複。這是Opdyke 和Johnson 所描述過的“重分解以一般化”的一個很好的例子。首先識別現有代碼中的不同之處,並且將不同之處分離爲新的操作。最後,用一個調用這些新的操作的模板方法來替換這些不同的代碼。控制子類擴展。模板方法只在特定點調用“hook ”操作,這樣就只允許在這些點進行擴展。

三,實例

AbstractClass

package com.neei.template;

/**
 * @param
 * @Author: AaNeei
 * @Date: 2019/10/13  16:59
 * @Description: 豆漿製作
 * @throws:
 */
public abstract class SoyaMilk {

    //模板執行方法,不讓子類覆蓋
    final void make() {
        select();
        if(customerWantCondiments()){
            addCondiments();
        }
        soak();
        beat();
    }

    //選材
    void select() {
        System.out.println("選擇好豆子");
    }

    //添加配料
    abstract void addCondiments();

    //浸泡
    void soak() {
        System.out.println("浸泡材料");
    }

    //研磨
    void beat() {
        System.out.println("放入豆漿機研磨");
    }

    //鉤子方法:是否需要加配料
    boolean customerWantCondiments() {
        return true;
    }
}

ConcreteClass

package com.neei.template;

/**
 * @param
 * @Author: AaNeei
 * @Date: 2019/10/13  17:04
 * @Description: 遊學網
 * @throws:
 */
public class RedBeanSoyaMilk extends SoyaMilk {
    @Override
    void addCondiments() {
        System.out.println("加人紅豆");
    }
}

public class PeanutSoyaMilk extends SoyaMilk {
    @Override
    void addCondiments() {
        System.out.println("加入花生");
    }
}
public class PureSoyaMilk extends SoyaMilk {

    @Override
    void addCondiments() {
        //空實現
    }

    @Override
    boolean customerWantCondiments() {
        //純豆漿不需要加配料
        return false;
    }
}

調用

package com.neei.template;

/**
 * @param
 * @Author: AaNeei
 * @Date: 2019/10/13  17:06
 * @Description: 遊學網
 * @throws:
 */
public class Client {
    public static void main(String[] args) {
        System.out.println("製作花生豆漿");
        SoyaMilk peanutSoyaMilk = new PeanutSoyaMilk();
        peanutSoyaMilk.make();
        System.out.println();
        System.out.println("製作紅豆豆漿");
        SoyaMilk redBeanSoyaMilk = new RedBeanSoyaMilk();
        redBeanSoyaMilk.make();
        System.out.println();
        System.out.println("製作純豆漿");
        SoyaMilk pureSoyaMilk = new PureSoyaMilk();
        pureSoyaMilk.make();
    }
}

四,源碼分析

Spring源碼中使用的模板方法模式,如org.springframework.context.support.AbstractApplicationContext#refresh

	//模板方法
	@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// 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 {
				// 鉤子方法
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				initMessageSource();

				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();

				// 鉤子方法
				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 Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
			}
		}
	}
	protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
		//待子類實現
		refreshBeanFactory();
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();//待子類實現
		if (logger.isDebugEnabled()) {
			logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
		}
		return beanFactory;
	}
	protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException;
	@Override
	public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
	
	protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	//空實現,提供鉤子,可以讓子類靈活重寫,實現不同功能
	}
	protected void onRefresh() throws BeansException {
		// For subclasses: do nothing by default.
		//空實現,提供鉤子,可以讓子類靈活重寫,實現不同功能
	}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章