【设计模式】模板方法与策略模式的结合使用

1. 概述

模板方法是一种非常简单的设计模式,只要能够理解面向对象中的继承与多态就能够理解这种设计模式,我们可以在很多的框架源码中找到它的身影。
同时在我们的日常开发中,它一般是用在同类型且不同实现方式的业务逻辑中,抽取公共逻辑,简单的说就是,模板方法经常和策略模式结合使用

本篇后续的代码中会涉及到策略模式,如果还不太熟悉策略模式使用实例的同学,可以先看一下上一篇文章:《SpringBoot优雅使用策略模式》

1.1.简述模板方法

模板方法通过继承来实现,顶层是一个抽象类,用于封装通用函数,并提供一个或多个抽象方法,下层是多个实现类,用于实现不同的业务逻辑分支,类图如下:
在这里插入图片描述

2.模板方法实现

实际使用的时候,一般会通过子类的实例调用父类中的模板方法templateMethod,在模板方法中调用抽象方法,最终还是会调用到子类中覆写的实例方法,这是一种常见的钩子函数使用方式。

2.1.简单实现

  • 抽象父类:
    /**
     * 抽象父类
     */
    public abstract class BaseClass {
        final public void templateMethod() {
            System.out.println("执行模板方法");
            method1();
            method2();
        }
    
        abstract protected void method1();
    
        abstract protected void method2();
    }
    
  • 子类实现
    /**
     * 子类1
     */
    public class ChildClass1 extends BaseClass {
        @Override
        protected void method1() {
            System.out.println("执行子类1的方法1");
        }
        @Override
        protected void method2() {
            System.out.println("执行子类1的方法2");
        }
    }
    
    /**
     * 子类2
     */
    public class ChildClass2 extends BaseClass {
        @Override
        protected void method1() {
            System.out.println("执行子类2的方法1");
        }
        @Override
        protected void method2() {
            System.out.println("执行子类2的方法2");
        }
    }
    

简单的测试一下:

public static void main(String[] args) {
    BaseClass baseClass = new ChildClass1();
    baseClass.templateMethod();

    baseClass = new ChildClass2();
    baseClass.templateMethod();
}

打印出测试结果:
在这里插入图片描述

2.2.在SpringBoot中的实现

在使用SpringBoot进行开发的时候,我们通常不会手动去创建对象,而是将不同的已经创建好的bean结合起来使用,我们可以在子类的对象中,通过@Autowired将其他的bean注入进来,并在运行时执行方法调用。

如果这个方法调用是通用的,我们可以将它抽取到的父类中去,但由于父类是抽象类无法实例化,自然也无法直接通过@Autowired注入bean,此时可以对子类做一点小改造,通过构造函数对父类进行赋值。

实现起来也非常的简单,下面是代码示例:

  • 首先提供一个QueryService供子类注入
    import org.springframework.stereotype.Service;
    
    @Service
    public class QueryService {
    
        public void query() {
            System.out.println("执行查询方法");
        }
    
    }
    
  • 其次需要再抽象父类中定义QueryService
    public abstract class BaseClass {
    
        protected QueryService queryService;
    
        final public void templateMethod() {
            System.out.println("执行模板方法");
            queryService.query();
            method1();
        }
    
        abstract protected void method1();
    
    }
    
  • 最后,在子类中注入并对父类的QueryService赋值
import org.springframework.stereotype.Component;

/**
 * 子类1
 */
@Component
public class ChildClass1 extends BaseClass {

    public ChildClass1(QueryService queryService) {
        super.queryService = queryService;
    }

    @Override
    protected void method1() {
        System.out.println("执行子类1的方法1");
    }

}
/**
 * 子类2
 */
@Component
public class ChildClass2 extends BaseClass {

    public ChildClass2(QueryService queryService) {
        super.queryService = queryService;
    }

    @Override
    protected void method1() {
        System.out.println("执行子类2的方法1");
    }
    
}

使用ApplicationContext做一个简单的测试:

@Component
public class Test implements ApplicationContextAware {

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        applicationContext.getBean(ChildClass1.class).templateMethod();
        applicationContext.getBean(ChildClass2.class).templateMethod();
    }
}

在这里插入图片描述

3.模板方法与策略模式的结合使用

模板方法与策略模式天然的可以结合使用,为了大家能够有个更直观的感受,我把两个类图放到一起,大家可以做一下对比。
在这里插入图片描述
在这里插入图片描述
相信大家也很容易可以看出来,如果我们现在业务中通过策略模式,让程序能够自行选择需要使用的子类实例,只需要再加上一个选择器就好了。

3.1.代码实现

上篇文章 中已经介绍了如何构建选择器,有需要的同学可以去看一下,在这里就不过多赘述,直接放实现代码。

只需要两个步骤就可以完成改造:

  • 第一步,编写策略选择器选择器枚举

    import org.jetbrains.annotations.NotNull;
    import org.springframework.beans.BeansException;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    import org.springframework.stereotype.Component;
    
    import java.util.Map;
    import java.util.stream.Collectors;
    
    /**
     * 策略选择器
     */
    @Component
    public class Selector implements ApplicationContextAware {
    
        private Map<String, BaseClass> selectorMap;
    
        public BaseClass select(String type) {
            return selectorMap.get(type);
        }
    
        @Override
        public void setApplicationContext(@NotNull ApplicationContext applicationContext) throws BeansException {
            this.selectorMap = applicationContext.getBeansOfType(BaseClass.class).values().stream()
                    .filter(strategy -> strategy.getClass().isAnnotationPresent(SelectorAnno.class))
                    .collect(Collectors.toMap(strategy -> strategy.getClass().getAnnotation(SelectorAnno.class).value(), strategy -> strategy));
        }
    }
    
    import java.lang.annotation.*;
    
    /**
     * 选择器注解
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.TYPE})
    @Inherited
    @Documented
    public @interface SelectorAnno {
    
        String value();
    
    }
    
  • 第二步:在两个子类中分别加入枚举

    @Component
    @SelectorAnno("child1")
    public class ChildClass1 extends BaseClass{
    }
    
    @Component
    @SelectorAnno("child2")
    public class ChildClass2 extends BaseClass {
    }
    

改造完成之后,模拟一下调用端发起请求,做一个简单的测试:

import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

@Component
public class Test {

    private final Selector selector;

    public Test(Selector selector) {
        this.selector = selector;
    }

    @PostConstruct
    public void test() {
        // 模拟调用端传入策略标识
        this.doInvoke("child1");
    }

    public void doInvoke(String type) {
        BaseClass baseClass = selector.select(type);
        baseClass.templateMethod();
    }

}

这里模拟的是调用端传入child1,选择子类1进行测试,打印的结果为:

执行模板方法
执行查询方法
执行子类1的方法1

4.总结

本篇文章介绍了什么是模板方法、模板方法的简单实现与在SpringBoot中的实现的。然后对比了模板方法与策略模式的类图,发现两者天然就可以结合在一起使用。最后,通过代码实现验证了两者结合使用的可行性。

当然,本篇文章中的都是简单的示例代码,突出的只是实现的思想,在日常的开发中,可以结合实际的业务流程对上述的代码进行改造。

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
设计模式(Design Pattern)是前辈们对代码开发经验的总结,是解决特定问题的一系列套路。它不是语法规定,而是一套用来提高代码可复用性、可维护性、可读性、稳健性以及安全性的解决方案。工厂模式、抽象工厂模式、单例模式、建造者模式、原型模式、适配器模式、装饰者模式、代理模式、外观模式、桥接模式、组合模式、享元模式策略模式模板方法模式、观察者模式、迭代器模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式 ### 设计模式的三大类 **创建型模式(Creational Pattern):**对类的实例化过程进行了抽象,能够将软件模块中**对象的创建**和对象的使用分离。 (5种)工厂模式、抽象工厂模式、单例模式、建造者模式、原型模式 情景记忆:两个人在聊天。一个问:这家**工厂**是干什么的?另一个说:**造 圆型 丹**药的。5个。 **结构型模式(Structural Pattern)**:关注于对象的组成以及对象之间的依赖关系,描述如何将类或者对象结合在一起形成更大的结构,就像**搭积木**,可以通过简单积木的组合形成复杂的、功能更为强大的结构。 (7种)适配器模式、装饰者模式、代理模式、外观模式、桥接模式、组合模式、享元模式 情景记忆:想象自己正在一个,无论是**外观**还是内部**装饰**都很豪华的度假村,**享**受着7天的带薪年假,那里有小**桥**流水,有**组合**了东西方文化的美食,有会说各国语言的服务员(即**适配器**),还可以**代理**预订各国各航班机票。7个。 **行为型模式(Behavioral Pattern)**:关注于对象的行为问题,是对在不同的对象之间划分责任和算法的抽象化;不仅仅关注类和对象的结构,而且重点关注它们之间的**相互作用**。 (11种)策略模式模板方法模式、观察者模式、迭代器模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式 情景记忆:一个**访客**来到一家房屋**中介**门口,正在**观察**宣传栏里的房屋信息,偶然间听到店长对一位新人说:“你向客人推荐房屋的**策略**用错了,你应该用**迭代**的方式介绍所有房源。客人走后,登记客人信息的**模板**也用错了。你的师傅没有向你**解释**清楚,他也有**责任**。我**命令**你用笔记记下我刚才说的话,起到**备忘**的目的”。店长走后,那位新人的**状态**很低落。
完整清晰版,完美书签. 《研磨设计模式》完整覆盖GoF讲述的23个设计模式并加以细细研磨。初级内容从基本讲起,包括每个模式的定义、功能、思路、结构、基本实现、运行调用顺序、基本应用示例等,让读者能系统、完整、准确地掌握每个模式,培养正确的“设计观”;中高级内容则深入探讨如何理解这些模式,包括模式中蕴涵什么样的设计思想,模式的本质是什么,模式如何结合实际应用,模式的优缺点以及与其他模式的关系等,以期让读者尽量去理解和掌握每个设计模式的精髓所在。   《研磨设计模式》在内容上深入、技术上实用、和实际开发结合程度很高,书中大部分的示例程序都是从实际项目中简化而来,因此很多例子都可以直接拿到实际项目中使用。如果你想要深入透彻地理解和掌握设计模式,并期望能真正把设计模式应用到项目中去,那么这是你不可错过的一本好书。   《研磨设计模式》难度为初级到中级,适合与所有开发人员、设计人员或者即将成为开发人员的朋友。也可以作为高效学生深入学习设计模式的参考读物! 第1章 设计模式基础    第2章 简单工厂    第3章 外观模式    第4章 适配器模式(Adapter)    第5章 单例模式(Singleton)    第6章 工厂方法模式(Factory Method)    第7章 抽象工厂模式(Abstract Factory)    第8章 生成器模式(Builder)    第9章 原型模式(Prototype)    第10章 中介者模式(Mediator)    第11章 代理模式(Proxy)    第12章 观察者模式(Observer)    第13章 命令模式(Command)    第14章 迭代器模式(Iterator)    第15章 组合模式(Composite)    第16章 模板方法模式(Template Method)    第17章 策略模式(Strategy)    第18章 状态模式(State)    第19章 备忘录模式(Memento)    第20章 享元模式(Flyweight)    第21章 解释器模式(Interpreter)    第22章 装饰模式(Decorator)    第23章 职责链模式(Chain of Responsibility)    第24章 桥接模式(Bridge)    第25章 访问者模式(Visitor)    附录A常见面向对象设计原则    附录BUML简介    参考文献
本电子书一共两个压缩文档,本文件为part2. 《研磨设计模式》完整覆盖GoF讲述的23个设计模式并加以细细研磨。初级内容从基本讲起,包括每个模式的定义、功能、思路、结构、基本实现、运行调用顺序、基本应用示例等,让读者能系统、完整、准确地掌握每个模式,培养正确的“设计观”;中高级内容则深入探讨如何理解这些模式,包括模式中蕴涵什么样的设计思想,模式的本质是什么,模式如何结合实际应用,模式的优缺点以及与其他模式的关系等,以期让读者尽量去理解和掌握每个设计模式的精髓所在。    《研磨设计模式》在内容上深入、技术上实用、和实际开发结合程度很高,书中大部分的示例程序都是从实际项目中简化而来,因此很多例子都可以直接拿到实际项目中使用。如果你想要深入透彻地理解和掌握设计模式,并期望能真正把设计模式应用到项目中去,那么这是你不可错过的一本好书。    《研磨设计模式》难度为初级到中级,适合与所有开发人员、设计人员或者即将成为开发人员的朋友。也可以作为高效学生深入学习设计模式的参考读物! 第1章 设计模式基础    第2章 简单工厂    第3章 外观模式    第4章 适配器模式(Adapter)    第5章 单例模式(Singleton)    第6章 工厂方法模式(Factory Method)    第7章 抽象工厂模式(Abstract Factory)    第8章 生成器模式(Builder)    第9章 原型模式(Prototype)    第10章 中介者模式(Mediator)    第11章 代理模式(Proxy)    第12章 观察者模式(Observer)    第13章 命令模式(Command)    第14章 迭代器模式(Iterator)    第15章 组合模式(Composite)    第16章 模板方法模式(Template Method)    第17章 策略模式(Strategy)    第18章 状态模式(State)    第19章 备忘录模式(Memento)    第20章 享元模式(Flyweight)    第21章 解释器模式(Interpreter)    第22章 装饰模式(Decorator)    第23章 职责链模式(Chain of Responsibility)    第24章 桥接模式(Bridge)    第25章 访问者模式(Visitor)    附录A常见面向对象设计原则    附录BUML简介    参考文献

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

挥之以墨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值