模板方法模式 之 实际生产使用方式

  模板方式模式可以说是设计模式中比较简单的一类,简单的说其实现过程是多态的扩展,为什么这么说呢?下面具体介绍一下模板方法模式的概念及实际生产使用情况。(理解不到位请见谅啊!)

  模板方法模式简单的说就是抽象父类定义抽象方法及运作流程,子类继承以实现具体工作。举个简单的例子: 男生洗头和女生洗头之间的差别,(以不洗澡,只洗头为例)首先对洗头这件事情主要有一下几个流程: 准备---->挤洗发液---->清洗---->吹干(比较邋遢,洗一次就行了)。

public abstract class WashHair {
    //准备阶段
    protected abstract void prepare();
    //挤洗发液
    protected abstract void extrudedShampoo();
    //清洗
    protected abstract void wash();
    //吹干
    protected abstract void dry();
    //流程
    public void templateMethod() {
        prepare();
        extrudedShampoo();
        wash();
        dry();
    }
}

  那么到男生开始洗头了,流程如下: 脱衣服(光膀子)----> 拧起沐浴露---->一顿抓----->风干。

public class ManWashHair extends WashHair {

    @Override
    protected void prepare() {
        // TODO Auto-generated method stub
        System.out.println("光着膀子");
    }

    @Override
    protected void extrudedShampoo() {
        // TODO Auto-generated method stub
        System.out.println("拧起沐浴露");
    }

    @Override
    protected void wash() {
        // TODO Auto-generated method stub
        System.out.println("一顿狂抓");
    }

    @Override
    protected void dry() {
        // TODO Auto-generated method stub
        System.out.println("自然风干");
    }

}

  男生洗头比较粗糙,不讲究。现在女生开始洗头,当然肯定不能脱光膀子是吧,准备(不能耍流氓,过程不说了)---->选择洗发液---->按摩清洗(其实估计也没这么讲究)---->吹风机。

public class WamanWashHair extends WashHair{

    @Override
    protected void prepare() {
        // TODO Auto-generated method stub
        System.out.println("准备");
    }

    @Override
    protected void extrudedShampoo() {
        // TODO Auto-generated method stub
        System.out.println("选择洗发液,护发素");
    }

    @Override
    protected void wash() {
        // TODO Auto-generated method stub
        System.out.println("按摩清洗");
    }

    @Override
    protected void dry() {
        // TODO Auto-generated method stub
        System.out.println("吹风机吹干");
    }

}

  好,现在基本代码都写完了,我们先说好处再来测试。优点: 解耦,首先我们不在直接操作男生或者女生这个对象,而是操作我们的抽象类。其次方便扩展,这一点很重要,比如在公司里面有一个流程很多业务都需要使用,但是每一个业务都自己编写相同的一套流程太low了,而且新的业务增加时还需要再写一遍重复的流程,如果使用模板方法模式,就可以直接扩展,在调用的时候直接调用就行。缺点:增加了代码的可阅读性,为什么这么说?简单的解释,这样子类的实现过程直接影响父类的执行结果。

  测试一下:

public class WashMain {
    public static void main(String[] args) {
        //将子类向上转型为父抽象类
        WashHair manWashHair = new ManWashHair();
        WashHair womanWashHair = new WomanWashHair();
        //男女生分别执行洗头
        manWashHair.templateMethod();
        womanWashHair.templateMethod();
    }
}

  现在模板方法工厂学习完成,那么在实际生产中会不会这么搞呢?其实也可以,但是不灵活,给大家介绍原来一个项目的解决方案,使用xml来解决。在上面的例子中我们发现我们建立的模板是方法层面上面的,就是说直接调用的是方法,但是在实际生产中则侧重于类层面的(不知道这么说是不是符合专业用语啊!),同时也有方法侧面,下面给大家介绍一个建房的例子(自己想的,如果业务逻辑不对的话就将就看吧)。

  建房需要这么几个步骤,买地---->准建审批---->招募工程队---->修建,这样一个详细的过程,其中涉及到公司修建和个人修建(小城市)。下面简单介绍一下两者不同的实现过程,

    首先公司买地需要开会,造价计算,而个人则是衡量自身的经济水平,准备资金。

    准建审批,公司需要提供公司资历,提交修建保证金,个人则需要提交保证金,请领导吃饭。

    招募工程队,公司需要招标,投标公司资历审核,决标成交,个人则需要打听哪个包工头技术好,商讨价格即可。

  下面是详细的实现过程。

  针对买地,审批,招募,修建的代码不做展示,将代码的目录结构放出来。

  

  具体看看build的过程,通过Build入口方法build来执行,通过spring setter方法注入buyLand,audit,conscribe的不同实现类(分为company和person)。

package com.module.entry;

import com.module.audit.Audit;
import com.module.buyland.BuyLand;
import com.module.conscribe.Conscribe;

/**
 * 
 * Project Name:Model
 * ClassName:Build
 * Description:
 * @author: libo
 * @date: 2018年11月10日 下午4:54:42
 * note:主要完成修建的过程,在类的层面上实现模板方法模式
 *
 */
public class Build {
    //通过spring注入
    private BuyLand buyLand;
    
    private Audit audited;
    
    private Conscribe conscribe;
    
    //具体修建过程
    public void build() {
        buyLand.excute();
        audited.excute();
        conscribe.excute();
    }

    public BuyLand getBuyLand() {
        return buyLand;
    }

    public void setBuyLand(BuyLand buyLand) {
        this.buyLand = buyLand;
    }

    public Audit getAudited() {
        return audited;
    }

    public void setAudited(Audit audit) {
        this.audited = audit;
    }

    public Conscribe getConscribe() {
        return conscribe;
    }

    public void setConscribe(Conscribe conscribe) {
        this.conscribe = conscribe;
    }
    
}

  下面是spring的配置文件,通过spring的配置文件可以轻松的决定整个修建过程的注入类,这样方便修改和扩展。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <!-- 采用xml注入的方式分别注入buyLand,Audit,conscribe的实现类 也可以配置自动扫描来进行注解注入 两种方式都可以-->
    <bean id="companyBuyLand" class="com.module.buyland.CompanyBuyLand"></bean>
    
    <bean id="personBuyLand" class="com.module.buyland.PersonBuyLand"></bean>
    
    <bean id="companyAudited" class="com.module.audit.CompanyAudited"></bean>
    
    <bean id="personAudited" class="com.module.audit.PersonAudited"></bean>
    
    <bean id="companyConscribe" class="com.module.conscribe.CompanyConscribe"></bean>
    
    <bean id="personConscribe" class="com.module.conscribe.PersonConscribe"></bean>
    <!--通过注入不同的实现类来完成不同的工作--> 
    <bean id="personBuild" class="com.module.entry.Build">
        <property name="buyLand" ref="personBuyLand"></property>
        <property name="audited" ref="personAudited"></property>
        <property name="conscribe" ref="personConscribe"></property>
    </bean>       
    <bean id="companyBuild" class="com.module.entry.Build">
        <property name="buyLand" ref="companyBuyLand"></property>
        <property name="audited" ref="companyAudited"></property>
        <property name="conscribe" ref="companyConscribe"></property>
    </bean>       
         
        
        
        
</beans>

  下面是main函数及运行结果:

  在原来的项目中,一个架构师使用这种方式完成订单框架的基本结构,并且完成通过spring进行流程内业务的配置,觉得很牛逼,如果我在这写的不清楚或者有错误,望见谅!如果你有更好的理解,也请留言告诉我,谢谢!

原文地址:https://www.cnblogs.com/liboBlog/p/9940194.html