5

使用面向对象和功能性方法来重构Java应用

 1 year ago
source link: https://blog.51cto.com/u_7390037/5372973
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

使用面向对象和功能性方法来重构Java应用

原创

WOT技术大会 2022-06-10 13:34:24 ©著作权

文章标签 java 面向对象 封装 文章分类 Java 编程语言 阅读数157

使用面向对象和功能性方法来重构Java应用_面向对象

本文将和您讨论如何使用面向对象和功能性两种方法,来实现更好的设计与 Java 应用重构,并以继承和功能性接口的示例形式,展示了两者在实现上的区别。

在重构方面,Java主要有两种主要方法,即:面向对象(object-oriented)和功能性(functional)。其中,前者几乎是从Java第一版就存在了,而功能性始于2014年3月推出的Java 1.8。

PART 01

面向对象和功能性方法

作为一种经典的面向对象语言,Java允许用户创建灵活的对象结构。在Java 1.8出现了功能性特性之后,它不仅可以使用对象或方法,还可以使用lambdas(其本身是可执行代码,https://dzone.com/articles/java-lambda-method-reference)进行各项操作。而在功能性的世界中,您可以像在OO的世界中使用对象那样,去操作各种功能。

使用面向对象和功能性方法来重构Java应用_面向对象_02

PART 02

使用OO方法重构代码

通过使用继承或组合的方式来处理各种接口和类,您可以创建出各种可重用的通用方案,从而减少程序的代码量,并提高可读性。如果一个类满足了如下的条件,那么它便可以在相同的公共结构中进行联合:

  • 具有相似的字段,并被识别为同一实体
  • 有父/子(parent/children)关系
  • 有相似目的的方法

PART 03

使用功能性方法重构代码

与OO方法不同,这种方法提取具有相同行为的代码。例如,我们可以在如下两个示例中识别出相似之处:

  • 在具体实现上能够返回相同类型
  • 在具体实现上有相同的功能

PART 04

使用两种方法进行重构的示例

假设我们有一个小型应用程序,其功能向正式员工(Employee)和合同工(Contractor)支付工资。每次完成支付工资后,我们都会打印一份Employee报告,并以不同的格式显示(https://dzone.com/articles/so-much-data-so-many-formats-a-conversion-service),即:正式员工为JSON格式,而合同工为XML格式。以下便是使用两种方法重构的示例:

使用面向对象和功能性方法来重构Java应用_java_03

现在让我们来看一下其默认结构:

使用面向对象和功能性方法来重构Java应用_面向对象_04

PART 05

重构类的结构

很明显,Contractor可以成为Employee类的子类。同时,makePayment可以被覆盖掉。当然,我们也可以创建一个Payable接口和提取makePayment的方法,不过让我们在此保持简单化。如下代码段所示,在重构之后,我们产生了一些共同的字段,以及可重用的构造函数。

使用面向对象和功能性方法来重构Java应用_java_05

PART 06

重构功能性

现在我们可以从功能性的角度,来回顾和发掘源代码中的相似之处:

使用面向对象和功能性方法来重构Java应用_面向对象_06

如上图所示,从打印报告中可以看出,我们可以使用相同的方式来进行处理,即:传递一个对象,并返回一个字符串。因此,我们可以将代码部分提取为一个可重用的功能,并将其动态地用于该业务的逻辑上。我们甚至可以将其拿到该业务的外部进行使用。

PART 07

创建功能接口

为了判定正确的功能性接口(如,Predicate、Consumer、Function等),我们需要检查自己的输入和输出。在本例中,我们得到的是一个Object,并需要将其转换为String。

使用面向对象和功能性方法来重构Java应用_面向对象_07

该接口是由功能函数提供的。为了更加便于理解,我们用serialize方法创建一个自有的Converter接口。其对应的代码如下,具有极强的可读性:

使用面向对象和功能性方法来重构Java应用_封装_08

PART 08

创建Lambda

转换器(Converter)功能性接口

下面,我们可以在功能性接口的基础上,创建两个转换器:JSON和XML。它们都会去匹配已定义的签名,即:对象输入(Object Input)和字符串输出(String Output)。

使用面向对象和功能性方法来重构Java应用_封装_09

接着,让我们在代码中使用它们:

使用面向对象和功能性方法来重构Java应用_面向对象_10

PART 09

在Employee类中封装转换器

与前面的方法类似,我们可以将此功能封装在Employee父类中,并在内部功能函数中使用它们。下图展示了如何在Employee类中封装转换器:

使用面向对象和功能性方法来重构Java应用_封装_11

PART 10

审查最终版本

最后,我们初始化两个employee类,并遍历它们的支付执行情况和打印方法。

使用面向对象和功能性方法来重构Java应用_面向对象_12

我们将最终得到:

  • Employee父类中的Commons字段和方法被重用到了Contractor中
  • 可以在无需更改Employee类的情况下,提取功能函数转换器(我们可以在未来再做补充)
  • 提取的功能函数可以在Employee类之外被重用

PART 11

点评    

总的说来,上述示例并不完美,且有待改进。例如,我们可以将Employee与Contractors类隐藏在接口的后面。您也可以试着去写一个简单的例子,以便只展示一些面对对象和功能特性。

当然,从严格意义上说,我创建的功能可能并非纯功能。而一些开发人员往往坚持认为:在Java中只有纯功能才是更好的。在此,我持保留意见。

PART 12

小结    

让我们对上述内容小结一下:

  • 使用面向对象的方法,我们可以将性质相似(similar-by-nature)的对象统一到同一个结构中。
  • 使用功能性方法,我们则可以统一功能相似(similar-by-functionality)的代码。

这两种方法都能够让程序代码的可读性和可维护性得到显著提高。

原文链接:

 ​https://dzone.com/articles/refactoring-java-application-object-oriented-and-f​


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK