This is the seventh day of my participation in the August More text Challenge. For details, see:August is more challenging

Design patterns

WangScaler: an author who works with his heart.

Statement: talent and learning shallow, if there is a mistake, kindly correct.

Template method pattern

What is a template pattern? For example, three people go to A bank for business. A wants to deposit money, B wants to withdraw money, and C wants to transfer money. However, before they want to complete their business, they have to take a number, queue up, and after the business, they have to evaluate.

The process of taking numbers, queuing and evaluation of these three people is the same, so we can extract them out and let the parent class achieve, as for the business of these three people are different, can only be implemented in the subclass.

So the template method pattern is to define the skeleton of an algorithm in an operation and defer some of the steps of the algorithm (doing business) to the subclasses so that the subclasses can redefine certain steps of the algorithm without changing the structure of the algorithm.

To write a template pattern, first find the invariant parts (numbering, queuing, evaluation) and implement them in the parent class. Since our process of picking, queuing, and evaluating is invariant and does not need to be overridden by subclasses, we can define it as final.

Bank.java

package com.wangscaler.template;
​
/ * * *@author WangScaler
 * @date2021/7/12 19:52 * /public abstract class Bank {
    final void getNumber(a) {
        System.out.println("Take no.");
    }
​
    final void lineUp(a) {
        System.out.println("Line up");
    }
​
    abstract void business(a);
​
    final void evaluate(a) {
        System.out.println("Evaluation"); }}Copy the code

Abstract mutable parts for subclasses to implement. Deposit business

SaveMoney.java

package com.wangscaler.template;
​
/ * * *@author WangScaler
 * @date 2021/7/27 13:54
 */public class SaveMoney extends Bank {
    @Override
    void business(a) {
        System.out.println("Save"); }}Copy the code

The business of withdrawing money

package com.wangscaler.template;
​
/ * * *@author WangScaler
 * @date2021/7/27 13:53 * /public class WithdrawMoney extends Bank {
​
    @Override
    void business(a) {
        System.out.println("Withdraw money"); }}Copy the code

main

package com.wangscaler.template;
​
/ * * *@author WangScaler
 * @date2021/7/27 plague * /public class Tempalte {
    public static void main(String[] args) {
        Bank saveMoneyPeople = new SaveMoney();
        saveMoneyPeople.businessForBank();
        Bank withdrawMoneyPeople = newWithdrawMoney(); withdrawMoneyPeople.businessForBank(); }}Copy the code

This is a typical template pattern.

Hook method

In a parent class, you define an empty method that does nothing by default. It is up to the child class to override this method. This method is called a hook method. Hook methods make your code more flexible, giving the user access to whether or not they need to implement it.

Because we go to the bank to withdraw money, when we take the number of the queue process, maybe because there are too many people in front of you, maybe there are other things you need to deal with, maybe you are waiting in the bank to blow air conditioning, and so on, finally did not go to the business, there is no evaluation.

Since the business can be evaluated only after the business has been handled, we need to add a method to judge whether the business has been implemented or not, and override the judgment method if not. The modified bank.java

package com.wangscaler.template;
​
/ * * *@author WangScaler
 * @date2021/7/12 19:52 * /public abstract class Bank {
    final void businessForBank(a) {
        getNumber();
        lineUp();
        business();
        if(handleBusiness()) { evaluate(); }}final void getNumber(a) {
        System.out.println("Take no.");
    }
​
    final void lineUp(a) {
        System.out.println("Line up");
    }
​
    void business(a){}final void evaluate(a) {
        System.out.println("Evaluation");
    }
​
    boolean handleBusiness(a) {
        return true; }}Copy the code

If a subclass does not handleBusiness, then it overrides the judgment method handleBusiness. Since business is a hook method, we do not need to implement it, so we do not need to write it.

package com.wangscaler.template;
​
/ * * *@author WangScaler
 * @date2021/7/27 14:27 * /public class Play extends Bank {
    @Override
    boolean handleBusiness(a) {
        return false; }}Copy the code

main

package com.wangscaler.template;
​
/ * * *@author WangScaler
 * @date2021/7/27 plague * /public class Tempalte {
    public static void main(String[] args) {
        Bank saveMoneyPeople = new SaveMoney();
        saveMoneyPeople.businessForBank();
        Bank withdrawMoneyPeople = new WithdrawMoney();
        withdrawMoneyPeople.businessForBank();
        Bank playPeople = newPlay(); playPeople.businessForBank(); }}Copy the code

So playPeople. BusinessForBank (); Only the action of taking numbers and queuing will be triggered.

Template method in source code

Initialization of the SpringIOC container.

public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
public void refresh(a) throws BeansException, IllegalStateException {
        synchronized(this.startupShutdownMonitor) {
            this.prepareRefresh();
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            this.prepareBeanFactory(beanFactory);
​
            try {
                this.postProcessBeanFactory(beanFactory);
                this.invokeBeanFactoryPostProcessors(beanFactory);
                this.registerBeanPostProcessors(beanFactory);
                this.initMessageSource();
                this.initApplicationEventMulticaster();
                this.onRefresh();
                this.registerListeners();
                this.finishBeanFactoryInitialization(beanFactory);
                this.finishRefresh();
            } catch (BeansException var9) {
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
                }
​
                this.destroyBeans();
                this.cancelRefresh(var9);
                throw var9;
            } finally {
                this.resetCommonCaches(); }}}protected ConfigurableListableBeanFactory obtainFreshBeanFactory(a) {
        this.refreshBeanFactory();
        return this.getBeanFactory();
    }
    protected abstract void refreshBeanFactory(a) throws BeansException, IllegalStateException;
    public abstract ConfigurableListableBeanFactory getBeanFactory(a) throws IllegalStateException;
     protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {}protected void onRefresh(a) throws BeansException {}}Copy the code

AbstractApplicationContext postProcessBeanFactory and onRefresh are empty in the implementation, namely the hook method in the template method, equivalent to the business in our example.

The refresh method corresponds to businessForBank in our example above, and the refreshBeanFactory and getBeanFactory methods are abstract methods that refer to business before we use the hook method.

So in a subclass we’re going to implement abstract methods, so let’s go to a subclass.

public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
protected final void refreshBeanFactory(a) throws BeansException {
        if (this.hasBeanFactory()) {
            this.destroyBeans();
            this.closeBeanFactory();
        }
​
        try {
            DefaultListableBeanFactory beanFactory = this.createBeanFactory();
            beanFactory.setSerializationId(this.getId());
            this.customizeBeanFactory(beanFactory);
            this.loadBeanDefinitions(beanFactory);
            this.beanFactory = beanFactory;
        } catch (IOException var2) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var2); }}public final ConfigurableListableBeanFactory getBeanFactory(a) {
        DefaultListableBeanFactory beanFactory = this.beanFactory;
        if (beanFactory == null) {
            throw new IllegalStateException("BeanFactory not initialized or already closed - call 'refresh' before accessing beans via the ApplicationContext");
        } else {
            returnbeanFactory; }}Copy the code

This subclass implements only abstract methods. None of the hook methods are implemented. Let’s look for a subclass that implements the hook method.

Sure enough, found in subclasses AbstractRefreshableWebApplicationContext of its subclasses.

public abstract class AbstractRefreshableWebApplicationContext extends AbstractRefreshableConfigApplicationContext implements ConfigurableWebApplicationContext.ThemeSource {
    protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
        beanFactory.ignoreDependencyInterface(ServletContextAware.class);
        beanFactory.ignoreDependencyInterface(ServletConfigAware.class);
        WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
        WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
    }
    protected void onRefresh(a) {
        this.themeSource = UiApplicationContextUtils.initThemeSource(this);
    }
    protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
        beanFactory.ignoreDependencyInterface(ServletContextAware.class);
        beanFactory.ignoreDependencyInterface(ServletConfigAware.class);
        WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
        WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig); }}Copy the code

conclusion

Several types of template patterns

  • Abstract methods: Declared in abstract classes and implemented by concrete subclasses.
  • Concrete methods: already implemented in abstract classes, which can be inherited or overridden in concrete subclasses.
  • Hook methods: implemented in abstract classes, including logical methods for judgment and empty methods that need to be overridden by subclasses.

Usage scenario:

You can use the template method pattern when you need a series of steps to accomplish something that are basically the same, but may differ in the implementation of individual steps.

Disadvantages:

  • If there are many implementations of individual steps, then we need to write many subclasses to inherit.
  • If a superclass adds a new abstract method, then all subclasses must inherit, which is one of the reasons design rules avoid inheritance.

The resources

  • JAVA Design Patterns
  • Template method
  • Template pattern