您当前的位置:首页 > 电脑百科 > 程序开发 > 语言 > JAVA

如何提高 Java 代码的可重用性

时间:2024-01-03 14:05:18  来源:51CTO  作者:

译者 | 刘汪洋

审校 | 重楼

对于软件开发者而言,编写可重用的代码是一项基本而重要的技能。每位工程师都应掌握如何尽可能地提高代码的复用性。当前,一些开发人员可能会认为微服务的本质是小而高效,因此他们无需编写高质量代码。然而,即便是微服务,在变得庞大时,阅读和理解代码的时间成本也会迅速增加至编写时的十倍。

如何提高 Java 代码的可重用性

代码一开始编写得不佳,将会大幅增加修复 bug 或添加新功能的工作量。在一些极端情况下,我见证过团队因代码质量问题而放弃原有代码,重新编写。这不仅浪费了宝贵时间,还可能导致开发人员承担责任并失去工作。

本文将介绍经过实践验证的提高JAVA 中代码可重用性的八条指导原则。

Java 编程中编写可重用代码的八大指导原则

  1. 制定编码规范
  2. 记录 API 文档
  3. 遵守代码命名规范
  4. 提高代码内聚性
  5. 代码解耦
  6. 遵循 SOLID 原则
  7. 合理运用设计模式
  8. 避免重复造轮子

制定编码规范

编写可重用代码的首要步骤是与团队一同确立代码规范。如果对编码规范不能达成共识,代码很快就会变得混乱不堪。如果团队成员之间意见不统一,关于代码实现的无效讨论也会频繁发生。同时,你需要确立一个基础的代码设计框架,以解决软件需要解决的问题。

在制定了标准和代码设计框架之后,接下来应当明确代码指导原则。

常见的指导原则包括:

  • 代码命名规范
  • 类和方法的行数限制
  • 异常处理方式
  • 包结构设计
  • 编程语言及其版本
  • 所使用的框架、工具和库
  • 代码测试标准
  • 代码结构层次(如控制器、服务、存储库、领域等)

一旦团队就这些规范达成共识,每个成员都应对代码审查负责,以确保编写出高质量、可重用的代码。如果没有共识,写出高质量且可重用的代码几乎不可能。

记录 API 文档

当创建服务并以 API 形式公开时,应该详细记录 API 信息,以便新加入的开发人员能够轻松理解和使用。

API 在微服务架构中扮演着重要角色。因此,对你的项目不太熟悉的其他团队成员必须能够通过阅读 API 文档来理解其功能。如果 API 文档记录不当,代码的重复编写风险会增加。新开发人员可能会无意中创建一个和现有功能重复的方法。

因此,精确记录 API 至关重要。但在代码中过度使用文档可能并无益处。应该只记录 API 中的关键信息,如业务操作的解释、参数、返回值对象等。

遵守代码命名规范

简洁且具有描述性的代码命名总是优于晦涩难懂的缩写。浏览不熟悉的代码库时,我发现缩写往往难以让人立即理解其含义。

因此,相较于使用像Ctr这样的缩写,直接命名为Customer更为明晰和有意义。Ctr可能代表了合同(contract)、控制(control)、客户(customer)等多种含义,使人难以确定其准确意图。

此外,要遵循你所使用编程语言的命名规范。以 Java 为例,它有 JavaBeans 命名规范,这对每个 Java 开发者来说都是基本常识。以下是 Java 中类、方法、变量和包的命名方式:

  • 类名采用 PascalCase(帕斯卡命名法):如CustomerContract
  • 方法和变量采用 camelCase(驼峰命名法):如customerContract
  • 包名全部小写:如service

提高代码内聚性

内聚的代码应该专注于_做好一件事_。虽然这是一个简单的概念,但即便是经验丰富的开发人员也常常忽视它。这样,他们就会创建出所谓的_超级复杂类_,即一个承担了过多职责的类,有时也被称为_全能类_。

要实现高内聚的代码,关键是学会拆分代码,确保每个类和方法专注于单一职责。比如,如果你创建了一个名为saveCustomer的方法,它应当只负责一个动作:保存客户信息。它不应该同时负责更新和删除客户信息。

同理,如果有一个名为CustomerService的类,它应该仅包含与客户相关的功能。如果CustomerService类中有执行产品相关操作的方法,应移至ProductService类中。

与其在CustomerService类中添加执行产品操作的方法,不如在该类中引用ProductService,并调用我们所需的任何方法。

为了更清晰地介绍这个概念,我们来分析一个低内聚的类示例:

public class CustomerPurchaseService {

    public void saveCustomerPurchase(CustomerPurchase customerPurchase) {
         // 执行与客户相关的操作
        registerProduct(customerPurchase.getProduct());
         // 更新客户信息
         // 删除客户信息
    }

    private void registerProduct(Product product) {
         // 在客户领域中执行对产品的逻辑操作…
    }

}

这个类存在以下问题:

  • saveCustomerPurchase方法不止注册产品,还涉及到更新和删除客户的操作。这个方法承担了过多的职责。
  • registerProduct方法在当前位置难以被其他开发者发现。因此,如果其他开发者需要类似的功能,可能会不必要地重写这个方法。
  • registerProduct方法处于不恰当的领域。CustomerPurchaseService不应负责注册产品。
  • saveCustomerPurchase方法调用了一个私有方法,而不是委托给专门处理产品操作的外部类。

识别出这些问题后,我们可以重新编写这段代码,使其变得更加内聚。我们将registerProduct方法移动到更合适的位置,即ProductService类中。这样做使代码更易于搜索和重用,同时避免将此方法局限在CustomerPurchaseService中:

public class CustomerPurchaseService {

    private ProductService productService;

    public CustomerPurchaseService(ProductService productService) {
      this.productService = productService;
    }

    public void saveCustomerPurchase(CustomerPurchase customerPurchase) {
         // 仅执行与客户购买相关的操作
        productService.registerProduct(customerPurchase.getProduct());
    }

}

public class ProductService {

   public void registerProduct(Product product) {
         // 在产品领域中执行相关逻辑…
    }
}

在这个改进后的版本中,saveCustomerPurchase仅执行其主要职责:保存客户购买信息。同时,registerProduct方法的职责被正确地委托给了ProductService类,从而使两个类都更加专注和内聚。现在,这些类及其方法都专注于执行预期的特定任务。

代码解耦

_高度耦合的代码_指的是那些具有过多依赖关系的代码,这种情况会导致代码难以维护。类中定义的依赖(其他类)越多,其耦合程度就越高。

微服务架构的目标之一就是将服务解耦,如果一个微服务与其他服务都有连接,那么它就会高度耦合。

想要更好地实现代码复用,就需要尽可能使系统和代码各自独立。虽然服务和代码之间的通信不可避免会产生一定程度的耦合,但关键在于让这些服务尽可能保持独立性。

下面是一个高度耦合类的例子:

public class CustomerOrderService {

  private ProductService productService;
  private OrderService orderService;
  private CustomerPaymentRepository customerPaymentRepository;
  private CustomerDiscountRepository customerDiscountRepository;
  private CustomerContractRepository customerContractRepository;
  private CustomerOrderRepository customerOrderRepository;
  private CustomerGiftCardRepository customerGiftCardRepository;

  // 其他方法…
}

注意CustomerService类与许多其他服务类的耦合程度很高。这么多的依赖意味着该类将包含大量代码,这不利于代码的测试和维护。

更有效的方法是拆分这个类,创造多个依赖更少的服务。我们可以通过将CustomerService类分解为独立的服务来降低其耦合度:

public class CustomerOrderService {

  private OrderService orderService;
  private CustomerPaymentService customerPaymentService;
  private CustomerDiscountService customerDiscountService;

  // 省略其他方法…
}

public class CustomerPaymentService {

  private ProductService productService;
  private CustomerPaymentRepository customerPaymentRepository;
  private CustomerContractRepository customerContractRepository;
  
  // 省略其他方法…
}

public class CustomerDiscountService {
  private CustomerDiscountRepository customerDiscountRepository;
  private CustomerGiftCardRepository customerGiftCardRepository;

  // 省略其他方法…
}

经过这样的重构,CustomerService及其他类变得更易于进行单元测试,同时也更便于维护。类的职责越单一且清晰,就越容易实现新功能。如果出现 bug,也更容易进行修复。

遵循 SOLID 原则

SOLID 代表面向对象编程(OOP)中五个关键的设计原则,它们的目标是使软件系统更加可维护、灵活,并易于理解。
下面是这些原则的简要说明:

  • 单一职责原则(SRP):一个类应该仅承担一个职责或目标,并且完全封装这个职责。这个原则促进_高内聚_,帮助保持类的专注和易于管理。
  • 开放封闭原则(OCP):软件实体(如类、模块、函数等)应该对扩展开放,对修改封闭。应设计代码以便在不更改现有代码的情况下增加新功能,从而减少更改的影响并促进代码重用。
  • 里氏替换原则(LSP):超类的任何实例都应该能被其子类的实例替换,而不影响程序的正确性。换言之,基类的任何实例都应该可以用其派生类的实例替换,保证程序行为的一致性。
  • 接口隔离原则(ISP):客户端不应被迫依赖它们不需要的接口。建议将大型接口拆分为更小且更具体的接口,使得客户端仅需依赖它们真正需要的接口。这有助于松耦合和避免不必要的依赖。
  • 依赖反转原则(DIP):高层模块不应依赖低层模块,两者都应依赖抽象。鼓励使用抽象(接口或抽象类)来解耦高层模块和低层实现细节,促进基于抽象而非具体实现的依赖。

遵循这些 SOLID 原则有助于开发者编写更模块化、可维护且易于扩展的代码。这些原则有助于实现更易于理解、测试和修改的代码,从而形成更健壮、适应性更强的软件系统。

合理运用设计模式

设计模式是经验丰富的开发者在处理多种编码场景后总结出的最佳实践。恰当地使用设计模式可以显著提升代码的复用性。

掌握设计模式还能增强你阅读和理解代码的能力——这包括 JDK 中的代码。当你能识别出其背后的设计模式时,代码会变得更加清晰。

尽管设计模式有其用处,但并非每种模式适用于所有情况,因此使用时需谨慎。仅仅因为我们了解某个模式,并不意味着就应该随意应用。在不恰当的场景中使用设计模式可能会使代码变得更复杂、更难以维护。然而,在合适的场合应用设计模式,可以使代码更加灵活和易于扩展。

以下是面向对象编程中常见的设计模式简要概述:

创建型模式

  • 单例(Singleton):确保一个类仅有一个实例,并提供一个全局访问点。
  • 工厂方法(Factory Method):定义一个用于创建对象的接口,但由子类决定实例化哪个类。
  • 抽象工厂(Abstract Factory):提供一个接口,用于创建相关或依赖对象的族群。
  • 建造者(Builder):分离复杂对象的构建和表示。
  • 原型(Prototype):通过复制现有的实例来创建新实例。

结构型模式

  • 适配器(Adapter):将一个类的接口转换成客户端所期望的另一种接口。
  • 装饰器(Decorator):动态地为对象添加新的功能。
  • 代理(Proxy):为另一个对象提供一个代理或占位符,以控制对这个对象的访问。
  • 组合(Composite):将对象组合成树形结构,以表示部分整体的层次结构。
  • 桥接(Bridge):将抽象部分与其实现部分分离,使它们可以独立变化。

行为型模式

  • 观察者:在对象间建立一种一对多的依赖关系,使得当一个对象改变状态时,所有依赖它的对象都会自动收到通知并更新。
  • 策略:封装了一系列算法,并在运行时允许选择其中的一种。
  • 模板方法:在基类中定义一个算法的框架,并允许子类提供具体的实现。
  • 命令:将请求或简单操作封装成对象,这使得你可以使用不同的请求、队列或日志请求,并支持可撤销的操作。
  • 状态:当对象的内部状态改变时,允许对象改变其行为。
  • 迭代器:提供一种方法来顺序访问聚合对象的元素,而无需暴露其底层表示。
  • 责任链:允许请求沿着处理者链传递,直到一个处理者处理它。
  • 中介者:定义一个对象,该对象封装了一组对象如何交互的方式,从而促进它们之间的松散耦合。
  • 访问者:将算法从操作的对象中分离出来,将算法封装到一个称为访问者的对象中。

并不需要记住每一种设计模式,重要的是意识到这些模式的存在,并理解它们各自的使用场景。这样,你就能够根据具体的编程情境选择最合适的设计模式。

避免重复造轮子

许多公司在没有充分理由的情况下仍选择使用内部框架,但这对非大型科技公司来说通常是不现实的。对于中小型企业来说,与开源社区或大型科技公司竞争,开发出更优解决方案的可能性较低。

相比于重复发明轮子和制造不必要的工作,更理智的选择是直接利用已有的工具和技术。这不仅节省时间,还有助于开发人员的职业发展,因为他们无需学习只在公司内部使用的框架。

例如,Hibernate 是一个经过严格测试并被广泛使用的持久性框架。我遇到过的一家公司选择使用自己的内部框架进行持久化处理,尽管它并不具备 Hibernate 的全部功能和稳定性。维护和扩展这种内部框架给公司带来了额外负担,而没有带来相应的好处。

因此,建议尽可能使用市场上广泛可用且流行的技术和工具。开发一个能与成熟开源软件匹敌的框架几乎不可能,因为后者是众多才华横溢的开发者多年合作的成果。此外,许多大型公司也支持开源项目,确保它们能按预期运行。

结论

理解和应用代码复用性的关键原则对于构建高效且可维护的软件系统至关重要。通过掌握抽象、封装、关注点分离、标准化和文档化等关键概念,开发人员能创建可节省时间和减少重复工作的组件,同时提升代码质量。

设计模式对代码复用至关重要,提供了针对常见设计问题的经过验证过的解决方案。内聚性和低耦合确保组件独立且依赖性最小,提高了它们的复用性。遵循 SOLID 原则有助于创建模块化、可扩展的代码,易于集成到不同项目中。

编写可复用代码能够为开发人员带来诸多好处,包括提高生产力、加强协作和加快开发周期。可复用代码使项目迭代更快、维护更容易,能够有效利用现有解决方案。总之,掌握代码复用性的核心原则能够帮助开发人员构建可扩展、适应性强且面向未来的软件系统。

译者介绍

刘汪洋,51CTO社区编辑,昵称:明明如月,一个拥有 5 年开发经验的某大厂高级 Java 工程师,拥有多个主流技术博客平台博客专家称号。

原文标题:How to write reusable Java code,作者:Rafael del Nero



Tags:Java   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
17 个你需要知道的 JavaScript 优化技巧
你可能一直在使用JavaScript搞开发,但很多时候你可能对它提供的最新功能并不感冒,尽管这些功能在无需编写额外代码的情况下就可以解决你的问题。作为前端开发人员,我们必须了解...【详细内容】
2024-04-03  Search: Java  点击:(4)  评论:(0)  加入收藏
你不可不知的 15 个 JavaScript 小贴士
在掌握如何编写JavaScript代码之后,那么就进阶到实践——如何真正地解决问题。我们需要更改JS代码使其更简单、更易于阅读,因为这样的程序更易于团队成员之间紧密协...【详细内容】
2024-03-21  Search: Java  点击:(25)  评论:(0)  加入收藏
Oracle正式发布Java 22
Oracle 正式发布 Java 22,这是备受欢迎的编程语言和开发平台推出的全新版本。Java 22 (Oracle JDK 22) 在性能、稳定性和安全性方面进行了数千种改进,包括对Java 语言、其API...【详细内容】
2024-03-21  Search: Java  点击:(10)  评论:(0)  加入收藏
构建一个通用灵活的JavaScript插件系统?看完你也会!
在软件开发中,插件系统为应用程序提供了巨大的灵活性和可扩展性。它们允许开发者在不修改核心代码的情况下扩展和定制应用程序的功能。本文将详细介绍如何构建一个灵活的Java...【详细内容】
2024-03-20  Search: Java  点击:(20)  评论:(0)  加入收藏
Java 8 内存管理原理解析及内存故障排查实践
本文介绍Java8虚拟机的内存区域划分、内存垃圾回收工作原理解析、虚拟机内存分配配置,以及各垃圾收集器优缺点及场景应用、实践内存故障场景排查诊断,方便读者面临内存故障时...【详细内容】
2024-03-20  Search: Java  点击:(14)  评论:(0)  加入收藏
如何编写高性能的Java代码
作者 | 波哥审校 | 重楼在当今软件开发领域,编写高性能的Java代码是至关重要的。Java作为一种流行的编程语言,拥有强大的生态系统和丰富的工具链,但是要写出性能优异的Java代码...【详细内容】
2024-03-20  Search: Java  点击:(19)  评论:(0)  加入收藏
在Java应用程序中释放峰值性能:配置文件引导优化(PGO)概述
译者 | 李睿审校 | 重楼在Java开发领域,优化应用程序的性能是开发人员的持续追求。配置文件引导优化(Profile-Guided Optimization,PGO)是一种功能强大的技术,能够显著地提高Ja...【详细内容】
2024-03-18  Search: Java  点击:(23)  评论:(0)  加入收藏
对JavaScript代码压缩有什么好处?
对JavaScript代码进行压缩主要带来以下好处: 减小文件大小:通过移除代码中的空白符、换行符、注释,以及缩短变量名等方式,可以显著减小JavaScript文件的大小。这有助于减少网页...【详细内容】
2024-03-13  Search: Java  点击:(2)  评论:(0)  加入收藏
跨端轻量JavaScript引擎的实现与探索
一、JavaScript 1.JavaScript语言JavaScript是ECMAScript的实现,由ECMA 39(欧洲计算机制造商协会39号技术委员会)负责制定ECMAScript标准。ECMAScript发展史: 2.JavaScript...【详细内容】
2024-03-12  Search: Java  点击:(2)  评论:(0)  加入收藏
面向AI工程的五大JavaScript工具
令许多人惊讶的是,一向在Web开发领域中大放异彩的JavaScript在开发使用大语言模型(LLM)的应用程序方面同样大有价值。我们在本文中将介绍面向AI工程的五大工具,并为希望将LLM...【详细内容】
2024-02-06  Search: Java  点击:(52)  评论:(0)  加入收藏
▌简易百科推荐
Java 8 内存管理原理解析及内存故障排查实践
本文介绍Java8虚拟机的内存区域划分、内存垃圾回收工作原理解析、虚拟机内存分配配置,以及各垃圾收集器优缺点及场景应用、实践内存故障场景排查诊断,方便读者面临内存故障时...【详细内容】
2024-03-20  vivo互联网技术    Tags:Java 8   点击:(14)  评论:(0)  加入收藏
如何编写高性能的Java代码
作者 | 波哥审校 | 重楼在当今软件开发领域,编写高性能的Java代码是至关重要的。Java作为一种流行的编程语言,拥有强大的生态系统和丰富的工具链,但是要写出性能优异的Java代码...【详细内容】
2024-03-20    51CTO  Tags:Java代码   点击:(19)  评论:(0)  加入收藏
在Java应用程序中释放峰值性能:配置文件引导优化(PGO)概述
译者 | 李睿审校 | 重楼在Java开发领域,优化应用程序的性能是开发人员的持续追求。配置文件引导优化(Profile-Guided Optimization,PGO)是一种功能强大的技术,能够显著地提高Ja...【详细内容】
2024-03-18    51CTO  Tags:Java   点击:(23)  评论:(0)  加入收藏
Java生产环境下性能监控与调优详解
堆是 JVM 内存中最大的一块内存空间,该内存被所有线程共享,几乎所有对象和数组都被分配到了堆内存中。堆被划分为新生代和老年代,新生代又被进一步划分为 Eden 和 Survivor 区,...【详细内容】
2024-02-04  大雷家吃饭    Tags:Java   点击:(55)  评论:(0)  加入收藏
在项目中如何避免和解决Java内存泄漏问题
在Java中,内存泄漏通常指的是程序中存在一些不再使用的对象或数据结构仍然保持对内存的引用,从而导致这些对象无法被垃圾回收器回收,最终导致内存占用不断增加,进而影响程序的性...【详细内容】
2024-02-01  编程技术汇  今日头条  Tags:Java   点击:(68)  评论:(0)  加入收藏
Java中的缓存技术及其使用场景
Java中的缓存技术是一种优化手段,用于提高应用程序的性能和响应速度。缓存技术通过将计算结果或者经常访问的数据存储在快速访问的存储介质中,以便下次需要时可以更快地获取。...【详细内容】
2024-01-30  编程技术汇    Tags:Java   点击:(72)  评论:(0)  加入收藏
JDK17 与 JDK11 特性差异浅谈
从 JDK11 到 JDK17 ,Java 的发展经历了一系列重要的里程碑。其中最重要的是 JDK17 的发布,这是一个长期支持(LTS)版本,它将获得长期的更新和支持,有助于保持程序的稳定性和可靠性...【详细内容】
2024-01-26  政采云技术  51CTO  Tags:JDK17   点击:(88)  评论:(0)  加入收藏
Java并发编程高阶技术
随着计算机硬件的发展,多核处理器的普及和内存容量的增加,利用多线程实现异步并发成为提升程序性能的重要途径。在Java中,多线程的使用能够更好地发挥硬件资源,提高程序的响应...【详细内容】
2024-01-19  大雷家吃饭    Tags:Java   点击:(105)  评论:(0)  加入收藏
这篇文章彻底让你了解Java与RPA
前段时间更新系统的时候,发现多了一个名为Power Automate的应用,打开了解后发现是一个自动化应用,根据其描述,可以自动执行所有日常任务,说的还是比较夸张,简单用了下,对于office、...【详细内容】
2024-01-17  Java技术指北  微信公众号  Tags:Java   点击:(95)  评论:(0)  加入收藏
Java 在 2023 年仍然流行的 25 个原因
译者 | 刘汪洋审校 | 重楼学习 Java 的过程中,我意识到在 90 年代末 OOP 正值鼎盛时期,Java 作为能够真正实现这些概念的语言显得尤为突出(尽管我此前学过 C++,但相比 Java 影响...【详细内容】
2024-01-10  刘汪洋  51CTO  Tags:Java   点击:(74)  评论:(0)  加入收藏
站内最新
站内热门
站内头条