美文网首页
设计模式-模版方法模式(行为型)

设计模式-模版方法模式(行为型)

作者: NealLemon | 来源:发表于2019-08-15 21:39 被阅读0次

定义

  • 定义了一个行为的骨架,并允许子类为一个或多个步骤提供实现。
  • 模版方法使得子类可以在不改变行为结构的情况下,重新定义某些步骤。

适用场景

  • 一次性实现行为的不变的部分,并将可变的行为留给子类来实现。
  • 各子类中公共的行为被提取出来并集中到一个父类中,从而避免代码重复。

优点

  • 提高复用性。
  • 提高扩展性。
  • 符合开闭原则。

缺点

  • 类书目的增加。
  • 增加了系统实现的复杂度。
  • 继承关系自身缺点,如果父类添加新的抽象,子类都需要重新实现一遍。

代码

模版方法非常简单,相信很多小伙伴已经在使用了。我们来举一个比较通常的例子。

我们经常在业务中需要读取 excel,csv,txt,json等格式的数据,并且将他们清洗入库。

因此我们可以抽象一个模版

文件处理模版:

  • 读取文件
  • 清洗数据
  • 数据入库
  • 数据导出(钩子方法来判断)

注意:这里只是一个概念抽象,具体的实现请不要纠结

文件处理模版类(FileDataHandler

/**
 * 抽象父类
 */
public abstract class FileDataHandler {

    protected final void handleData() {
        readData();
        proccessData();
        intoDataBase();
        if(needExport()) {
            exportData();
        }
    }

    /**
     * 读取数据
     */
    final void readData() {
        System.out.println("----读取数据----");
    }

    /**
     * 清洗数据
     */
    final void proccessData() {
        System.out.println("----清洗数据-----");
    }

    /**
     * 数据入库
     */
    final void intoDataBase() {
        System.out.println("----数据入库-----");
    }

    /**
     * 导出数据
     */
    final void exportData() {
        System.out.println("----导出数据-----");
    }

    /**
     * 是否导出数据
     * @return
     */
    protected boolean needExport() {
        return false;
    }

    /**
     * 获取数据源
     */
    protected abstract void openSource();
}

这里看到 我们抽取固定的行为 已经定义为final修饰的方法,这样子类是无法重写的,保证了行为的一致性。

我们还添加了钩子方法needExport() 来选择行导出数据。

同时定义了抽象方法打开数据源,由于我们打开文件的源不同,但是这又是读取文件的必要操作,因此我们给他定义为一个抽象方法,这样强制子类去执行,防止子类没有初始化源的情况。

处理Excel (ExcelDataHandler)

/**
 * Excel文件处理类
 */
public class ExcelDataHandler extends FileDataHandler {
    @Override
    protected void openSource() {
        System.out.println("打开Excel文件");
    }
}

正常处理,没有导出操作。

处理JSON (JsonDataHandler)

/**
 * Json文件处理类
 */
public class JsonDataHandler extends FileDataHandler {
    @Override
    protected void openSource() {
        System.out.println("打开json文件");
    }

    /**
     * 激活钩子方法 导出
     * @return
     */
    @Override
    protected boolean needExport() {
        return true;
    }
}

这里打开了钩子,开启数据导出。

UML类图

templateUML.jpg

测试

public class TemplateBootstrap {

    public static void main(String[] args) {
        FileDataHandler excel = new ExcelDataHandler();
        excel.openSource();
        excel.handleData();
        System.out.println("----------------------------------");
        FileDataHandler json = new JsonDataHandler();
        json.openSource();
        json.handleData();

    }
}
templatere.jpg

其他开源使用

JDK

AbstractList :在AbstractList中,抽象出来了List下公共的行为方法。我们看一下源码就清楚了。

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
    /**
     * Sole constructor.  (For invocation by subclass constructors, typically
     * implicit.)
     */
    protected AbstractList() {
    }

    /**
     * Appends the specified element to the end of this list (optional
     * operation).
     *
     * <p>Lists that support this operation may place limitations on what
     * elements may be added to this list.  In particular, some
     * lists will refuse to add null elements, and others will impose
     * restrictions on the type of elements that may be added.  List
     * classes should clearly specify in their documentation any restrictions
     * on what elements may be added.
     *
     * <p>This implementation calls {@code add(size(), e)}.
     *
     * <p>Note that this implementation throws an
     * {@code UnsupportedOperationException} unless
     * {@link #add(int, Object) add(int, E)} is overridden.
     *
     * @param e element to be appended to this list
     * @return {@code true} (as specified by {@link Collection#add})
     * @throws UnsupportedOperationException if the {@code add} operation
     *         is not supported by this list
     * @throws ClassCastException if the class of the specified element
     *         prevents it from being added to this list
     * @throws NullPointerException if the specified element is null and this
     *         list does not permit null elements
     * @throws IllegalArgumentException if some property of this element
     *         prevents it from being added to this list
     */
    public boolean add(E e) {
        add(size(), e);
        return true;
    }

    /**
     * {@inheritDoc}
     *
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    abstract public E get(int index);

相信小伙伴一看就了解了。

SpringBoot

在Spring 中 有一个内容协商类 AbstractNamedValueMethodArgumentResolver 也将针对请求中的参数解析行为抽象成了一个父类。

public abstract class AbstractNamedValueMethodArgumentResolver implements HandlerMethodArgumentResolver {

   @Nullable
   private final ConfigurableBeanFactory configurableBeanFactory;

   @Nullable
   private final BeanExpressionContext expressionContext;
   //省略部分代码
    @Override
    @Nullable
    public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
            NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

        NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
        MethodParameter nestedParameter = parameter.nestedIfOptional();

        Object resolvedName = resolveStringValue(namedValueInfo.name);
        if (resolvedName == null) {
            throw new IllegalArgumentException(
                    "Specified name must not resolve to null: [" + namedValueInfo.name + "]");
        }

        Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest);
        if (arg == null) {
            if (namedValueInfo.defaultValue != null) {
                arg = resolveStringValue(namedValueInfo.defaultValue);
            }
            else if (namedValueInfo.required && !nestedParameter.isOptional()) {
                handleMissingValue(namedValueInfo.name, nestedParameter, webRequest);
            }
            arg = handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType());
        }
        else if ("".equals(arg) && namedValueInfo.defaultValue != null) {
            arg = resolveStringValue(namedValueInfo.defaultValue);
        }

        if (binderFactory != null) {
            WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
            try {
                arg = binder.convertIfNecessary(arg, parameter.getParameterType(), parameter);
            }
            catch (ConversionNotSupportedException ex) {
                throw new MethodArgumentConversionNotSupportedException(arg, ex.getRequiredType(),
                        namedValueInfo.name, parameter, ex.getCause());
            }
            catch (TypeMismatchException ex) {
                throw new MethodArgumentTypeMismatchException(arg, ex.getRequiredType(),
                        namedValueInfo.name, parameter, ex.getCause());

            }
        }

        handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);

        return arg;
    }
    //....

小结

模版方法模式很简单,但是确实体现了抽象意义。

相关文章

网友评论

      本文标题:设计模式-模版方法模式(行为型)

      本文链接:https://www.haomeiwen.com/subject/obgtsctx.html