0202年了!你还不知道模版方法设计模式?

简介: 0202年了!你还不知道模版方法设计模式?

01、什么是 Template ?

模版方法设计模式是一种行为型设计模式。官方定义理解比较隐晦,翻译成中文意思是这样的

模板方法模式在一个方法中定义一个 算法骨架,并将某些步骤推迟到 子类中实现。模板方法模式可以让子类在 不改变算法整体结构的情况下,重新定义算法中的某些步骤。

这里通过一个模版方法的UML类图来方便理解

通俗来讲 : 定义一个抽象类 AbstractTemplate,并定义一个或若干抽象方法 abstractMethod

由子类去继承抽象类的同时实现抽象方法, 在抽象类的 operation 方法中调用抽象方法,最终调用的就是不同子类实现的方法逻辑

这也就达到了官方所说的在不改变方法逻辑的情况下,重新定义了算法中的某些步骤

operation 对应官方解释里的 算法骨架abstractMethod 对应 某些步骤

读到这里不明白的朋友可以 细心看下UML类图,下面的实际应用也是根据此图进行的

02、为什么要用 Template

模版方法主要作用:复用性扩展性

复用性想必大家 日常都有使用,可能不清楚这是模版方法的特性之一

2.1 复用性

核心思想就是 父级定义公共实现由子级进行调取使用

举个例子大家就明白了,定义抽象发送消息,邮箱消息发送调取父类的 sendMessage 方法进行发送消息

这里使用 final 关键字就是不希望子类重写方法,实际应用根据场景来定义,有或没有都可以

public abstract class AbstractSendMessage {
    public final void sendMessage(Message message) {
        sendService.sendMessage(message);
    }
}

class EmailMessage extends AbstractSendMessage {
    public void sendEmailMessage(EmailMessage emailMessage) {
        Message message = buildMessage(emailMessage);
        super.sendMessage(message);
    }
}

是不是挺容易理解的,这只是复用特性的其中一种,还有几种方式都是大同小异

今天重点不在复用性,而是另外一个特性

2.2 扩展性

扩展性指的就是文初所说的,在不修改方法逻辑的前提下,变更其中的某些步骤。这里通过一个项目中实际场景来说明

03、实际运用

老规矩,先来说一下项目中是根据什么场景进行实际运用的

由于最近要重构一部分业务,原因是因为 处理数据量过大,SO

目前的思路是进行 多线程并发执行,具体业务以及解决思路不详细说明了

由于线程在项目中属于重要且珍贵的资源,阿里巴巴开发规范中明确规定 线程资源必须交由线程池进行管理。这次实际场景也是围绕 模版设计模式的扩展性来构造线程池

构造线程池

首先定义构建线程池的抽象类,其中 initParam 交由需要创建线程池的客户端实现具体细节

@Slf4j
public abstract class AbstractTreadPoolTemplate {

    // 构建初始化参数
    public abstract ThreadPoolInitParam initParam();

    // 构造线程池
    public ExecutorService buildPool() {
        ThreadPoolInitParam threadPoolInitParam = initParam();
        ExecutorService executorService =
                new ThreadPoolExecutor(threadPoolInitParam.corePoolNum,
                        threadPoolInitParam.maxPoolNum,
                        threadPoolInitParam.keepAliveTime,
                        threadPoolInitParam.timeUnit,
                        threadPoolInitParam.workQueue,
                        threadPoolInitParam.threadFactory,
                        threadPoolInitParam.rejectedExecutionHandler);
        return executorService;
    }
}

核心参数构建

由于阿里开发手册规范认为 JDK 推出 Executors 创建线程池的方法各有弊端

所以我们使用 JDK 原生的 ThreadPoolExecutor 来进行管理线程资源,但是核心参数需要根据 业务规模以及场景来定义

个人认为业务不到一定规模,正确使用 Executors 的话,并没有什么问题。这句话偷偷说,防止被怼 [笑哭]

ThreadPoolInitParam 提供有默认的参数,但是强烈推荐 根据业务量重载参数赋值方法

@Data : Lombok 提供注解,涵盖了好几个注解,自行百度吧

@Accessors(chain = true) 级联操作,set属性的方法返回对象本身

本来想使用 @RequiredArgsConstructor,考虑到还得打备注,算了吧

Lombok 不熟悉的朋友可以去点击公众号最新推送,里面有一篇介绍性文章涵盖了80%+的注解

@Data
@Accessors(chain = true)
public class ThreadPoolInitParam {
    private Integer doubleCpu = Runtime.getRuntime().availableProcessors() << 1;
    private Integer corePoolNum = doubleCpu + 1;
    private Integer maxPoolNum = doubleCpu << 1;
    private Long keepAliveTime = 0L;
    private TimeUnit timeUnit = TimeUnit.MILLISECONDS;
    private BlockingQueue workQueue = new ArrayBlockingQueue(500);
    private RejectedExecutionHandler rejectedExecutionHandler = new ThreadPoolExecutor.AbortPolicy();
    private ThreadFactory threadFactory;
    private String threadName;

    public ThreadPoolInitParam(String threadName, boolean isDaemon) {
        this.threadFactory = new InitThreadFactory(threadName, isDaemon);
        this.threadName = threadName;
    }
}

客户端实现

客户端这里通过 new 抽象类来进行重写 initParam 方法,并填入 ThreadPoolInitParam 需要的参数后创建自定义线程池

细心的读者可以看到创建线程池尾部使用的 buildPool() 方法,是不是有一丝构建的意思呢

没错,这里使用到了 构建者设计模式,只不过没有在文中进行体现,会由后续文章来进行讲解

@Bean("dataIsuExecutor")
public ExecutorService dataIsuExecutor() {
    return new AbstractTreadPoolTemplate() {
        @Override
        public ThreadPoolInitParam initParam() {
            return new ThreadPoolInitParam("dataIsuExecutor", false)
                    .setCorePoolNum(80)
                    .setMaxPoolNum(100)
                    .setKeepAliveTime(60000L)
                    .setWorkQueue(new ArrayBlockingQueue(800));
        }
    }.buildPool();
}

04、总结

到这里,带有实际场景的 模版方法设计模式 就讲完了,模版方法模式还是比较简单容易理解的

不过,看的设计模式多了之后,发现很多模式之间 大同小异。这个时候我们就需要知道不同设计模式对应的业务场景是什么,在合适的场景使用合理的模式,才能设计出 "好代码"

相关文章
|
7月前
|
设计模式 SQL 算法
设计模式了解哪些,模版模式
设计模式了解哪些,模版模式
65 0
|
7月前
|
设计模式 NoSQL Java
常用的设计模式以及操作Redis、MySQL数据库、各种MQ、数据类型转换的方法
常用的设计模式以及操作Redis、MySQL数据库、各种MQ、数据类型转换的方法
|
3月前
|
设计模式 算法 PHP
PHP中的设计模式:策略模式的深入探索与实践在软件开发的广袤天地中,PHP以其独特的魅力和强大的功能,成为无数开发者手中的得力工具。而在这条充满挑战与机遇的征途上,设计模式犹如一盏明灯,指引着我们穿越代码的迷雾,编写出更加高效、灵活且易于维护的程序。今天,就让我们聚焦于设计模式中的璀璨明珠——策略模式,深入探讨其在PHP中的实现方法及其实际应用价值。
策略模式,这一设计模式的核心在于它为软件设计带来了一种全新的视角和方法。它允许我们在运行时根据不同情况选择最适合的解决方案,从而极大地提高了程序的灵活性和可扩展性。在PHP这门广泛应用的编程语言中,策略模式同样大放异彩,为开发者们提供了丰富的创作空间。本文将从策略模式的基本概念入手,逐步深入到PHP中的实现细节,并通过一个具体的实例来展示其在实际项目中的应用效果。我们还将探讨策略模式的优势以及在实际应用中可能遇到的挑战和解决方案,为PHP开发者提供一份宝贵的参考。
|
5月前
|
设计模式
对抗软件复杂度问题之组合(Composite)方法设计模式是什么,如何解决
对抗软件复杂度问题之组合(Composite)方法设计模式是什么,如何解决
|
5月前
|
设计模式 算法
交易链路设计原则&模式问题之中介者(Mediator)方法设计模式是什么,如何解决
交易链路设计原则&模式问题之中介者(Mediator)方法设计模式是什么,如何解决
|
5月前
|
设计模式 Java
交易链路设计原则&模式问题之依赖倒置原则体现在实际应用中,如何解决
交易链路设计原则&模式问题之依赖倒置原则体现在实际应用中,如何解决
|
6月前
|
设计模式 机器学习/深度学习 JSON
文件读取的高效方法与设计模式
文件读取的高效方法与设计模式
46 0
|
设计模式 存储 Python
【从零学习python 】46. Python中的__new__和__init__方法解析及单例设计模式
【从零学习python 】46. Python中的__new__和__init__方法解析及单例设计模式
68 0
|
设计模式 程序员
设计模式 | 模版方法
设计模式 | 模版方法
84 0
|
7月前
|
设计模式 算法 自动驾驶
常见的设计模式(模板与方法,观察者模式,策略模式)
随着时间的推移,软件代码越来越庞大,随着而来的就是如何维护日趋庞大的软件系统。在面向对象开发出现之前,使用的是面向过程开发来设计大型的软件程序,面向过程开发将软件分成一个个单独的模块,模块之间使用函数进行组合,最后完成系统的开发,每次需要修改软件,如果不涉及好各个模块的关系,就会导致软件系统难以维护,从而导致软件变得不可使用。面向对象方法用对象模拟问题域中的实体,以对象间的联系刻画实体间联系
106 2