设计模式-模板模式

模板模式一般适用于有一定的流程,而且在不同的业务场景中有着不同的流程实现的情况。发布流程涉及到编译,备份,SQL执行,部署。这种情况下模板模式是一个不错的选择。

模板模式有时可以和组合模式一块使用,可以更能体现出Java面向接口编程的特性。

首先定义三个接口,分别代表流程中的不同的业务步骤

public interface StepOne {

    void doStepOne();
}
public interface StepTwo {
    
    void doStepTwo();
}
public interface StepThree {

    void doStepThree();
}

合并这些接口,用一个接口来代表所有接口,避免后面会有大量的冗余接口代码

public interface FullStep extends StepOne, StepTwo, StepThree {
}

接下来是定义模板,这里我会先定义一个规范模板的接口

public interface Process {
    void process();
//    Process nextProcess();
}

具体 模板实现

public abstract class ProcessImpl implements Process {

    private StepOne stepOne;

    private StepTwo stepTwo;

    private StepThree stepThree;


    @Override
    public void process() {

        if (stepOne != null) {

            stepOne.doStepOne();
        }

        if (stepTwo != null) {
            stepTwo.doStepTwo();
        }

        if (stepThree != null) {
            stepThree.doStepThree();
        }

        if (nextProcess() != null) {
            nextProcess().process();
        }
    }


    abstract Process nextProcess();
}

在抽象类ProcessImpl中,需要注入流程接口声明,这里我定义了三步,这里的

private StepOne stepOne;

private StepTwo stepTwo;

private StepThree stepThree;

怎么注入进去呢,由于这三个接口会被后面每一个具体的实现类实现,那么注入就是这些实现类共同要做的事情,所以可以把注入放在它们的公共父类来实现。所以我们需要一个公共父类

public abstract class FullProcess extends ProcessImpl implements FullStep {

    public void init() {
        setStepOne(this);
        setStepTwo(this);
        setStepThree(this);
    }

}

通过调用init方法便可以实现注入实现类对象到模板类的字段当中,这里还差一点,需要把这个类的调用自动化,那么需要用到spring的扩展接口。

public class OrderProcess extends FullProcess implements FullStep {


    @PostConstruct
    public void initialize() {
        super.init();
    }

    @Override
    Process nextProcess() {
        return null;
    }

    @Override
    public void doStepOne() {

    }

    @Override
    public void doStepThree() {

    }

    @Override
    public void doStepTwo() {

    }
}

这里我才用的是@PostConstruct注解,当然也可以采用实现InitializingBean接口,重写afterPropertiesSet()方法来实现。

OrderProcess公共实现创建完成后,便可以实现我们每一种流程对应的接口了,这里我实现了两个模板实现类。

public class ApProcess extends OrderProcess {

    @Override
    public void doStepOne() {
        System.out.println("AP step 1");
    }

    @Override
    public void doStepThree() {
        System.out.println("AP step 3");
    }

    @Override
    public void doStepTwo() {
        System.out.println("AP step 2");
    }
}
public class CenterProcess extends OrderProcess {

    @Override
    public void doStepOne() {
        System.out.println("Center step 1");
    }

    @Override
    public void doStepThree() {
        System.out.println("Center step 3");
    }

    @Override
    public void doStepTwo() {
        System.out.println("Center step 2");
    }
}

下面测试下

@SpringBootTest
@RunWith(SpringRunner.class)
public class ProcessTeset {

    @Autowired
    private ApplicationContext applicationContext;

    @Test
    public void test() {
        for (ProcessEnum value : ProcessEnum.values()) {
            Process process = (Process) applicationContext.getBean(value.getType());
            process.process();
        }
    }
}

测试结果

在这整个流程中,使用了模板模式和组合模式,具体的逻辑下沉的子类中实现。但是由于模板中的流程被拆分成了各个接口,所以需要把子类的实现注入到模板的属性中去,这样不仅可以规范模板的流程,还分离了流程中的每一个节点,比较方便。如果后期需要加节点,那么只需要加一个接口即可;如果需要修改节点逻辑,只需要修改接口签名或者修改实现类即可。总之可以做到流程的动态化。

详细的代码传到了GitHub上https://github.com/markytsai/design-demos。

原文地址:https://www.cnblogs.com/markytsai/p/13443245.html