Java教程

谈谈模板方法模式在实际生产的应用及代码复用

本文主要是介绍谈谈模板方法模式在实际生产的应用及代码复用,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

谈谈模板方法模式在实际生产的应用及代码复用

所谓模板方法

18 年,仍是个小白的时候写了一篇 谈谈模板方法模式

这篇文章也不想再复制一些难以读懂的概念,简而言之,模板方法就是提取一些公用代码到父类,然后由子类去具体实现父类里没有实现的代码逻辑,目的就是为了代码的复用

在生产里的应用及出现的问题

FTP 消费任务(完美贴合)

这个业务是这样的,由于系统运行在某个不可描述的内网里面,数据交换都是通过 FTP 服务器来进行的,所以当数据发送到 FTP 服务器之后,我们就需要定时拉取上面的文件下来,并自定义文件的业务处理流程,处理成功之后就需要把文件删除掉

所以就有了这么样的一个设计:

abstract class AbstractFtpConsumeJob extends Task {
  public void run() {
    var client = buildFtpClient();
    // 遍历 FTP 上的文件
    // 文件处理
    if (consume(file)) delete(file);
    // ...
  }
  abstract FTPClient buildFtpClient();
  // 其他待子类实现的抽象方法...}class ConcreteFtpJob extends AbstractFtpConsumeJob {
  boolean consume(file) {...}
  FTPClient buildFtpClient() {...}
  // 其他抽象方法实现}

这个设计直至现在用的仍很舒服,但经过了几次改进,主要就是当每次新定义任务时,子类基本上只要实现 consume 方法而已,所以我将 AbstractFtpConsumeJob 的所有抽象方法都替换成了 protected 的实现,这样不仅有了默认的实现,同时也满足子类自定义化的需求

远程接口基类(用得很难受)

同时由于业务的原因,需要从许多接口上爬取数据或者需要传递一些数据到三方接口上,这个设计就是提取公用的 HTTPClient 到基类,然后提供一个发送请求及转换响应的 protected 方法,类似下面:

abstract class BaseRemote {
  protected HTTPClient httpclient;
  protected Resposne execute(Request request){...}
  protected byte[] convertResponse(Response response){...}}

事实证明,这个设计很失败,由于选择了错误的代码复用方式,结果就导致了这个 BaseRemote 的子类的个性化需求基本上无法在基类上面复用,于是只能一层层继承往上套,一直小修小补

abstract class BaseBussiness1Remote extends BaseRemote {...}abstract class BaseBussiness2Remote extends BaseBussiness1Remote {...}

说说代码复用

对于有代码洁癖的人,一旦看到重复的代码就恨不得把它们提取出来,使用一个统一入口来管理,我早期也是这样的,但随着系统的演进,这种不加以评估的复用是有问题的

代码复用有风险

看到过许多人接手到一套屎山系统,为了实现一个简单的需求,改了一个小小的地方,需求是完成了,但另外一个看似不相关的地方甚至整个系统都崩了,这其中有一部分原因就是没有评估代码的复用所带来的的影响

所以在复用封装之前一定要评估好,如果一个方法复用另外一个方法之前,还需要看看这个方法的实现而非通过 API 来了解方法的具体作用,那这个封装复用就是失败的

先具体后抽象, 不要过早抽象

抽象也是代码复用的一种,对于上面构建的那些抽象基类,都不是从一开始就设计抽象类,都是从一堆堆极为相似的类中提取出来的

软件工程有句极为经典的话

过早优化是万恶之源

根据我的经验,过早抽象也是万恶之源,有些早期看似一样的代码,随着系统演进发展到后面会变得完全不一样,如果过早把它们抽取到同一个地方,一旦两个位置出现不同的需求,就会出现是改这个公用方法呢,还是改外部方法两难的境地

复用的方式

重构-代码抽取

这种方式的重用范围一般在本类的范围之内

void main() {
  // ...
  // ...}↓void main() {
  f1()
  // ...}void f1() {...}

另外一种就是工具类吗,工具类的代码复用就突破了作用域的限制,常见的 xxxUtils, xxxHelper 都是属于工具类

StringUtils.hasLength("cxk");RedisHelper.set("a", "b");

设计模式

许多设计模式都有代码复用的作用,最明显的当然就是模板方法模式

其他的诸如组合、单例等都有复用的作用


这篇关于谈谈模板方法模式在实际生产的应用及代码复用的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!