网站首页 > 文章中心 > 其它

java消除重复代码逻辑

作者:小编 更新时间:2023-08-26 10:53:29 浏览量:492人看过

常见代码重构技巧(非常实用)

①._代码重构漫画.jpeg

项目在不断演进过程中,代码不停地在堆砌.如果没有人为代码的质量负责,代码总是会往越来越混乱的方向演进.当混乱到一定程度之后,量变引起质变,项目的维护成本已经高过重新开发一套新代码的成本,想要再去重构,已经没有人能做到了.

造成这样的原因往往有以下几点:

对于此类问题,业界已有有很好的解决思路:通过持续不断的重构将代码中的"坏味道"清除掉.

根据重构的规模可以大致分为大型重构和小型重构:

大型重构 :对顶层代码设计的重构,包括:系统、模块、代码结构、类与类之间的关系等的重构,重构的手段有:分层、模块化、解耦、抽象可复用组件等等.这类重构的工具就是我们学习过的那些设计思想、原则和模式.这类重构涉及的代码改动会比较多,影响面会比较大,所以难度也较大,耗时会比较长,引入bug的风险也会相对比较大.

小型重构 :对代码细节的重构,主要是针对类、函数、变量等代码级别的重构,比如规范命名和注释、消除超大类或函数、提取重复代码等等.小型重构更多的是使用统一的编码规范.这类重构要修改的地方比较集中,比较简单,可操作性较强,耗时会比较短,引入bug的风险相对来说也会比较小.什么时候重构 新功能开发、修bug或者代码review中出现"代码坏味道",我们就应该及时进行重构.持续在日常开发中进行小重构,能够降低重构和测试的成本.

java消除重复代码逻辑-图1

代码重复

方法过长

过大的类

逻辑分散

严重的情结依恋

数据泥团/基本类型偏执

java消除重复代码逻辑-图2

不合理的继承体系

过多的条件判断

过长的参数列

临时变量过多

令人迷惑的暂时字段

纯数据类

不恰当的命名

过多的注释

代码质量的评价有很强的主观性,描述代码质量的词汇也有很多,比如可读性、可维护性、灵活、优雅、简洁.这些词汇是从不同的维度去评价代码质量的.其中,可维护性、可读性、可扩展性又是提到最多的、最重要的三个评价标准.

要写出高质量代码,我们就需要掌握一些更加细化、更加能落地的编程方法论,这就包含面向对象设计思想、设计原则、设计模式、编码规范、重构技巧等.

一个类只负责完成一个职责或者功能,不要存在多于一种导致类变更的原因.

单一职责原则通过避免设计大而全的类,避免将不相关的功能耦合在一起,来提高类的内聚性.同时,类职责单一,类依赖的和被依赖的其他类也会变少,减少了代码的耦合性,以此来实现代码的高内聚、松耦合.但是,如果拆分得过细,实际上会适得其反,反倒会降低内聚性,也会影响代码的可维护性.

java消除重复代码逻辑-图3

添加一个新的功能,应该是通过在已有代码基础上扩展代码(新增模块、类、方法、属性等),而非修改已有代码(修改模块、类、方法、属性等)的方式来完成.

开闭原则并不是说完全杜绝修改,而是以最小的修改代码的代价来完成新功能的开发.

子类对象(object of subtype/derived class)能够替换程序(program)中父类对象(object of base/parent class)出现的任何地方,并且保证原来程序的逻辑行为(behavior)不变及正确性不被破坏.

子类可以扩展父类的功能,但不能改变父类原有的功能

调用方不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上.接口隔离原则提供了一种判断接口的职责是否单一的标准:通过调用者如何使用接口来间接地判定.如果调用者只使用部分接口或接口的部分功能,那接口的设计就不够职责单一.

高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象.

一个对象应该对其他对象保持最少的了解

尽量使用合成/聚合的方式,而不是使用继承.

image.png

模块结构说明

代码开发要遵守各层的规范,并注意层级之间的依赖关系.

多个方法代码重复、方法中代码过长或者方法中的语句不在一个抽象层级.

方法是代码复用的最小粒度,方法过长不利于复用,可读性低,提炼方法往往是重构工作的第一步.

意图导向编程 :把处理某件事的流程和具体做事的实现方式分开.

将函数放进一个单独对象中,如此一来局部变量就变成了对象内的字段.然后你可以在同一个对象中将这个大型函数分解为多个小型函数.

方法参数比较多时,将参数封装为参数对象

任何有返回值的方法,都不应该有副作用

临时变量仅使用一次或者取值逻辑成本很低的情况下

将复杂表达式(或其中一部分)的结果放进一个临时变量,以此变量名称来解释表达式用途

把复杂的条件表达式拆分成多个条件表达式,减少嵌套.嵌套了好几层的if - then-else语句,转换为多个if语句

当出现大量类型检查和判断时,if else(或switch)语句的体积会比较臃肿,这无疑降低了代码的可读性. 另外,if else(或switch)本身就是一个"变化点",当需要扩展新的类型时,我们不得不追加if else(或switch)语句块,以及相应的逻辑,这无疑降低了程序的可扩展性,也违反了面向对象的开闭原则.

非正常业务状态的处理,使用抛出异常的方式代替返回错误码

某一段代码需要对程序状态做出某种假设,以断言明确表现这种假设.

当使用一个方法返回的对象时,而这个对象可能为空,这个时候需要对这个对象进行操作前,需要进行判空,否则就会报空指针.当这种判断频繁的出现在各处代码之中,就会影响代码的美观程度和可读性,甚至增加Bug的几率.

空引用的问题在Java中无法避免,但可以通过代码编程技巧(引入空对象)来改善这一问题.

根据单一职责原则,一个类应该有明确的责任边界.但在实际工作中,类会不断的扩展.当给某个类添加一项新责任时,你会觉得不值得分离出一个单独的类.于是,随着责任不断增加,这个类包含了大量的数据和函数,逻辑复杂不易理解.

此时你需要考虑将哪些部分分离到一个单独的类中,可以依据高内聚低耦合的原则.如果某些数据和方法总是一起出现,或者某些数据经常同时变化,这就表明它们应该放到一个类中.另一种信号是类的子类化方式:如果你发现子类化只影响类的部分特性,或者类的特性需要以不同方式来子类化,这就意味着你需要分解原来的类.

继承使实现代码重用的有力手段,但这并非总是完成这项工作的最佳工具,使用不当会导致软件变得很脆弱.与方法调用不同的是,继承打破了封装性.子类依赖于其父类中特定功能的实现细节,如果父类的实现随着发行版本的不同而变化,子类可能会遭到破坏,即使他的代码完全没有改变.

举例说明,假设有一个程序使用HashSet,为了调优该程序的性能,需要统计HashSet自从它创建以来添加了多少个元素.为了提供该功能,我们编写一个HashSet的变体.

通过在新的类中增加一个私有域,它引用现有类的一个实例,这种设计被称为组合,因为现有的类变成了新类的一个组件.这样得到的类将会非常稳固,它不依赖现有类的实现细节.即使现有的类添加了新的方法,也不会影响新的类.许多设计模式使用就是这种套路,比如代理模式、装饰者模式

继承与组合如何取舍

接口相比于抽象类的优势:

接口虽然提供了缺省方法,但接口仍有有以下局限性:

接口缺省方法的设计目的和优势在于:

为了接口的演化

可以减少第三方工具类的创建

可以避免创建基类

由于接口的局限性和设计目的的不同,接口并不能完全替换抽象类.但是通过对接口提供一个抽象的骨架实现类,可以把接口和抽象类的优点结合起来. 接口负责定义类型,或许还提供一些缺省方法,而骨架实现类则负责实现除基本类型接口方法之外,剩下的非基本类型接口方法.扩展骨架实现占了实现接口之外的大部分工作.这就是模板方法(Template Method)设计模式.

接口Protocol:定义了RPC协议层两个主要的方法,export暴露服务和refer引用服务

抽象类AbstractProtocol:封装了暴露服务之后的Exporter和引用服务之后的Invoker实例,并实现了服务销毁的逻辑

具体实现类XxxProtocol:实现export暴露服务和refer引用服务具体逻辑

由于为了保持Java代码的兼容性,支持和原生态类型转换,并使用擦除机制实现的泛型.但是使用原生态类型就会失去泛型的优势,会受到编译器警告.

每一条警告都表示可能在运行时抛出ClassCastException异常.要尽最大的努力去消除这些警告.如果无法消除但是可以证明引起警告的代码是安全的,就可以在尽可能小的范围中,使用@SuppressWarnings("unchecked")注解来禁止警告,但是要把禁止的原因记录下来.

还有一种特殊的无限制通配符List?,表示某种类型但不确定.常用作泛型的引用,不可向其添加除Null以外的任何对象.

嵌套类(nested class)是指定义在另一个类的内部的类. 嵌套类存在的目的只是为了它的外部类提供服务,如果其他的环境也会用到的话,应该成为一个顶层类(top-level class). 嵌套类有四种:静态成员类(static member class)、非静态成员类(nonstatic member class)、匿名类(anonymous class)和 局部类(local class).除了第一种之外,其他三种都称为内部类(inner class).

都说到这里了大家应该明白,这四种嵌套类都有自己的用途.假设这个嵌套类属于一个方法的内部,如果只需要在一个地方创建实例,并且已经有了一个预置的类型可以说明这个类的特征,就要把它做成匿名类.如果一个嵌套类需要在单个方法之外仍然可见,或者它太长了,不适合放在方法内部,就应该使用成员类.如果成员类的每个实例都需要一个指向其外围实例的引用,就要把成员类做成非静态的,否则就做成静态的.

通过对常见场景的代码逻辑进行抽象封装,形成相应的模板工具类,可以大大减少重复代码,专注于业务逻辑,提高代码质量.

面向对象编程相对于面向过程,多了实例化这一步,而对象的创建必须要指定具体类型.我们常见的做法是"哪里用到,就在哪里创建",使用实例和创建实例的是同一段代码.这似乎使代码更具有可读性,但是某些情况下造成了不必要的耦合.

对于顶层的(非嵌套的)类和接口,只有两种的访问级别:包级私有的(没有public修饰)和公有的(public修饰).

对于成员(实例/域、方法、嵌套类和嵌套接口)由四种的访问级别,可访问性如下递增:

不可变类是指其实例不能被修改的类.每个实例中包含的所有信息都必须在创建该实例时提供,并在对象的整个生命周期内固定不变.不可变类好处就是简单易用、线程安全、可自由共享而不容易出错.Java平台类库中包含许多不可变的类,比如String、基本类型包装类、BigDecimal等.

为了使类成为不可变,要遵循下面五条规则:

可变性最小化的一些建议:

TDD的最终目标是整洁可用的代码(clean code that works).大多数的开发者大部分时间无法得到整洁可用的代码.办法是分而治之.首先解决目标中的"可用"问题,然后再解决"代码的整洁"问题.这与体系结构驱动(architecture-driven)的开发相反.

采用TDD另一个好处就是让我们拥有一套伴随代码产生的详尽的自动化测试集.将来无论出于任何原因(需求、重构、性能改进)需要对代码进行维护时,在这套测试集的驱动下工作,我们代码将会一直是健壮的.

添加一个测试 - 运行所有测试并检查测试结果 - 编写代码以通过测试 - 运行所有测试且全部通过 - 重构代码,以消除重复设计,优化设计结构

避免重复代码:重复代码如何处理(仅供参考)

java 按照时间来统计 去除重复数据

你只需要考虑两点进行比较.

第一点:考虑用户ID,第二点:考虑时间

当你读取一条log信息的时候,取出用户ID和时间,

我不清楚你是实时的在执行往DB里面插入还是过一点时间整理,

如果是实时插入,那么你取出这个log信息的时候,就需要去现在的数据库里面进行匹配

如果在数据库查询出了这条数据,那么跳出,如果没有查询出结果,那么新增.

第二种情况,如果你是隔一段时间执行一次,那么你就只需要新建一个list集合,

然后用取出的log的集合循环和新的list数据进行匹配,如果遇到有的就跳出,如果在新的list集合里面没有的

那么就添加到新的list集合里面.

写的有点乱,我这里不建议你用list,这样匹配的时候循环工作量非常大,建议使用hashmap,键值对处理起来方便,

以用户ID为key 方便处理.

以上就是土嘎嘎小编为大家整理的java消除重复代码逻辑相关主题介绍,如果您觉得小编更新的文章只要能对粉丝们有用,就是我们最大的鼓励和动力,不要忘记讲本站分享给您身边的朋友哦!!

版权声明:倡导尊重与保护知识产权。未经许可,任何人不得复制、转载、或以其他方式使用本站《原创》内容,违者将追究其法律责任。本站文章内容,部分图片来源于网络,如有侵权,请联系我们修改或者删除处理。

编辑推荐

热门文章