23 개 디자인 패턴 (5) : 템플릿 메소드 패턴

1. 개념

그래서 비즈니스 요구에 따라 서브 클래스는 상위 클래스에 정의 된 알고리즘 프레임, 충전 프레임의 특정 단계를 구현합니다. 템플릿 메소드는 서브 클래스가 알고리즘의 구조를 변경하지 않고 알고리즘의 구현의 일부를 다시 정의 할 수 있습니다.

서브 클래스는 템플릿 메소드를 오버라이드 (override)하지 않는 것을 보장하기 위해, 템플릿 메소드는 final로 선언되어야합니다

2. 적용

  • 상위 클래스가 구현하는 알고리즘의 동일한 부분 및하자 아이 클래스는 행동의 변화 가능성을 구현합니다.
  • 피하기 코드 중복을 하나 개의 공통 클래스의 서브 클래스와이 분해 사이의 일반적인 행동.

프로그램의 3 예

등 지난해 심은 밀, 옥수수 심기 올해의 희망, 예를 들어 우리 삼촌 모돈 농가, 재배 과정이 크게으로 나누어 져있는 동안 : 등, 물 씨앗 파종의 구매에 관계없이 Zhongsha의,이 갈이 프로세스에 의해입니다 현상은, 그것은 템플릿 메소드 패턴에 기인한다.

우리는 그것을 달성하기 위해 특정 코드를 좀 봐!

3.1 추상 클래스는 핵심 알고리즘과 알고리즘 프레임 워크를 캡슐화

public abstract class AbstractPlantMethod {
    /**
     * 购买种子
     */
    public abstract String buySeeds();

    /**
     * 播撒
     */
    public abstract void sow(String seeds);

    /**
     * 浇水
     */
    public abstract void watering(String seeds);

    /**
     * 种植方法(定义为final,防止子类重写该核心算法)
     */
    public final void planting() {
        String seeds = this.buySeeds();
        this.sow(seeds);
        this.watering(seeds);
    }
}

3.2. 조파 밀

public class WheatMethod extends AbstractPlantMethod {
    @Override
    public String buySeeds() {
        System.out.println("购买小麦作物中...");
        return "wheats";
    }

    @Override
    public void sow(String seeds) {
        System.out.println("正在播撒" + seeds + "中...");
    }

    @Override
    public void watering(String seeds) {
        System.out.println("正在给" + seeds + "浇水中...");
    }


}

3.3. 심기 옥수수

public class CornMethod extends AbstractPlantMethod {
    @Override
    public String buySeeds() {
        System.out.println("购买玉米作物中...");
        return "corns";
    }

    @Override
    public void sow(String seeds) {
        System.out.println("正在播撒" + seeds + "中...");
    }

    @Override
    public void watering(String seeds) {
        System.out.println("正在给" + seeds + "浇水中...");
    }
}

3.4. 농부 삼촌

public class Farmers {
    private AbstractPlantMethod plantMethod;

    public Farmers(AbstractPlantMethod plantMethod) {
        this.plantMethod = plantMethod;
    }

    public void plant() {
        plantMethod.planting();
    }

    public void changeMethod(AbstractPlantMethod plantMethod) {
        this.plantMethod = plantMethod;
    }

}

3.5 클라이언트 호출

public class Client {
    public static void main(String[] args) {
        Farmers farmers = new Farmers(new WheatMethod());
        //播种小麦
        farmers.plant();
        farmers.changeMethod(new CornMethod());
        //播种玉米
        farmers.plant();
    }
}

3.6. 인쇄

购买小麦作物中...
正在播撒wheats中...
正在给wheats浇水中...
购买玉米作物中...
正在播撒corns中...
正在给corns浇水中...

템플릿 항에있어서 JDK1.8의 패턴에 사용 된

키 코드의 일부는 부모 클래스의 AbstractList를 아래 ArrayList를 우리가 매일 사용하고 있다고 생각하지만, 우리는 부모 클래스와 달성하기 위해 인터페이스에 대해 우려 적이 없습니다, 나는 나열했습니다.

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
   
    //get方法(抽象的方法,必须让子类按照自己的业务去实现)
    abstract public E get(int index);
    
    //addAll方法,允许子类去重写该方法,如果不重写,也可用父类中已经定义好的方法。
    public boolean addAll(int index, Collection<? extends E> c) {
        rangeCheckForAdd(index);
        boolean modified = false;
        for (E e : c) {
            add(index++, e);
            modified = true;
        }
        return modified;
    }
   
}

ArrayList에 그것의 핵심 코드를 살펴 보자

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
//实现的get方法
public E get(int index) {
        rangeCheck(index);

        return elementData(index);
    }
    
    //重写父类的addAll方法
    public boolean addAll(int index, Collection<? extends E> c) {
        rangeCheckForAdd(index);

        Object[] a = c.toArray();
        int numNew = a.length;
        ensureCapacityInternal(size + numNew);  // Increments modCount

        int numMoved = size - index;
        if (numMoved > 0)
            System.arraycopy(elementData, index, elementData, index + numNew,
                             numMoved);

        System.arraycopy(a, 0, elementData, index, numNew);
        size += numNew;
        return numNew != 0;
    }
}

스프링에 사용되는 템플릿 패턴 항에있어서,

시스템을 구축 할 때 서블릿 봄, 우리는 템플릿 메소드 패턴을 사용, 부모 클래스의 키 코드에서의 모습을 보자.

public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware {
    
    //重写了Javax提供的init方法,并将方法用final修饰,那么它的子类就没有权限修改init方法了
    @Override
	public final void init() throws ServletException {

		// Set bean properties from init parameters.
		PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
		if (!pvs.isEmpty()) {
			try {
				BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
				ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
				bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
				initBeanWrapper(bw);
				bw.setPropertyValues(pvs, true);
			}
			catch (BeansException ex) {
				if (logger.isErrorEnabled()) {
					logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
				}
				throw ex;
			}
		}

		// Let subclasses do whatever initialization they like.
		initServletBean();
	}
}

그리고 그 서브 클래스는 FrameworkServlet와 DispatcherServlet이이 방법의 일부를 다시 작성하기 만하면, 초기화 메소드를 오버라이드 (override) 갈 수 없어, 공통의 init 메소드입니다.

6. 요약

우리는 부모 클래스의 메소드를 수정하지 않는 서브 클래스로 원하는 경우에만 할 수있는 최종 수정을 추가해야합니다, 당신은 부모 클래스의 서브 클래스는 부모 클래스 추상적 인 수정을 사용하는 메소드를 오버라이드 (override) 할 필요가 원하는 경우, 서브 클래스는 변경 될 수있는 경우 당신이 오퍼레이션과 addAll 방법으로 할 수 있던대로 수정할 수 없습니다, 당신은 디자인 할 수 있습니다.

게시 39 개 원래 기사 · 13원 찬양 · 전망 2287

추천

출처blog.csdn.net/weixin_45612794/article/details/103957287