写优雅的代码规范的思路(入门篇)

注意:进行重构的第一步是你先能写出一种范式统一,注释清晰,内容优雅的代码。如果自觉不行请保持原状,不要伤害他,或者自己在本地练习。对于生产项目,这种时候最应该做的是顺着旧有项目的 “毛发” 捋下去,而不是进行优化或者另辟蹊径。项目的开发应该具备全局思维,不仅要考虑开发时候是否与业务贴切 ,也要考虑代码的质量和规范。好的质量和规范是为了后期维护和测试提前买了保险。(为什么有的人不用加班,有的人经常加班,除了钱的问题,大部分就在此)。这段话是本篇博客的核心,其他一切都可以丢弃哦~,网上说的重构随时可以开始,都是骗小屁孩的 ,你重构你就凉~~

一、介绍(主要两点)

1.提高代码复用率

2.避免低级BUG,出BUG必出重大级别的BUG的问题。(基础测试入门篇)

3.优秀的代码风格

 

二、主要类型

重构设计的思想原本是为了说修复代码而用,然而写出重构水准的代码是一个初级程序员必须具备的能力,这个也是由菜鸟到初级的分水岭。正常情况下需要重构的场景:

1.重复代码

2.过长的类(复杂)

3.过多的参数(>=3)

4.过于发散的类,意思是一个类处理两个截然不同的业务环节。比如Realm类处理登录校验,还做过滤处理。

5.散弹修改的类,意思是一个业务功能修改,需要在ABDCEF类中分别修改

6.依恋情结的类,意思是A类的方法调用B类的参数或者方法超过了类的一半以上,A类作为一个同等级对象,如果同学A和同学B

7.数据泥团,在多个地方出现多个数据在一起出现,应该将之捆绑为数据对象

8.基本数据类型,过多使用基本数据类型

9.平行集成体系,意思是增加A必须跟着增加B,应该进行实例继承。

10.由于重构或者功能删除而导致可以不必须独立存在的类

11.未来的类,为未来场景预设的类

12.未来的变量或字段,在某次添加的变量而没有使用上

13.过度耦合,如消息链,A想传递数据给C,但是A先传给了B再由B传给C

14.情侣类,两个类的私有变量交流过多,应该进行处理,比如私有变量get出来交互,话费过多。合并

15.异曲同工类,名字不一样,但是干的内容一致。比如报文类,应该设置基本报文类

16.纯数据类,单纯用于存放数据的类或者交付数据的类,这种类类似以前的数据字典,应该尽量避免或者剔除。(取消或成DTO)

17.被拒绝的馈赠,子类部分引用父类,很大一部分父类不用到,建立超父类,分别引用,保持父类纯粹

18.过多注释,应该尽量做到代码即注释。应该在节点进行注释,在入口进行需求+明确功能的注释;良好的注释为以后进行复用和维护奠定了基础。

 

三、处理的感觉

1、对于数量过多的函数,进行重组函数,提炼复杂的逻辑,将逻辑按照业务模块-方法功能组件-方法两类进行拆分。

2、内联函数,将功能明确而独立的逻辑 合并或者迁移到同个类中。在不违背面向对象编程(OOP)特性下,提炼到同个对象类成为新的函数。内联函数是在逻辑调用的节点,插入函数的本体。

注意:常规的手法有 迁移合并,内联函数调用(比如替换临时变量将表达式直接写入调用的节点,将函数名直接写入调用的节点)。但如果该方法存在着被子类继承的场景,那么应减少第二种内联手法。因为内联会导致内联的函数逻辑不向子类开发。

 

3、对于小功能函数,拒绝产生二次委托。除非是考虑进行 "委派和工厂模式" 的工具函数。(注释:小功能函数即是指功能独立,能脱离业务单独提供服务的方法函数组件。此类函数往往被用于提供输出和处理任务统一的功能,他可能是一个集合入口,当接收到参数后,将任务委派给其他函数执行最后统一响应。也可能是获取参数后,按照工厂流程进行处理最后输出不同的结果。此类功能函数类似于接口,只要求实现结果,内部逻辑如何实现不在乎,其内在可能随着架构的变迁或者项目的优化而变化,考虑到内部逻辑被改造或者被其他渠道取代而出入口不变的问题,因此需要进行 “包装”)。

4、复杂表达式 按照条件进行拆分。对于一个关联性极强的表达式或者逻辑,适当第将其按照一定步骤,一定阶段进行拆分。可降低代码复杂性。便于理解

5、临时变量赋值保持唯一。如果一个临时变量赋值被超过一次,也就说明了,她在这个活动中承担了不同的责职。一个变量多角色在二次开发或者维护会极大地增加开发者的负担。

6、应该移除对参数的赋值。当一个参数进入某个函数进行处理,这个函数应该有自己的局部参数(方法临时变量)用于数据的流转和结果的返回。而不应该借助入参的参数来回地赋值,或者将结果赋予入参参数返回。这样的函数会导致,逻辑与功能无法很好地分割。无法有效地执行替换和优化。(不清晰)。

7、拒绝被喂狗粮。如果一个类成为另外两个类频繁交流的场所,应该将这个交流的函数,迁移到这两个交流类中最主动或最常引用的类中。(耦合太多现象)

8、字段搬移。某个类的字段被另外类更多地使用到,可以在 该另外类建立一个新的字段。将责职迁移

9、类内联化。某个类存在(类即角色),已经没有再承担足够的责职,不再具备独立存在的理由,那么将其迁移合并到其他类中。

10、委托关系。客户类通过一个服务类调用另外一个对象类,那么为了隐藏委托关系。在该服务类上,应该在服务类上建立客户所需要的各种函数,以保证对象类信息不丢失。

注释:迪米特法则要求,一个对象应当对其他对象有尽可能少的了解,不和陌生人说话。也就是说,当委托关系存在,客户应该通过委托关系去了解自己所需要的数据和内容,并且保持这种关系的纯粹。但对象委托关系发生变化,客户类可以很快地知道这一层委托关系。而不是一个个去梳理。

11、提炼类。某个类做了应该由其他两个类做的事,建立一个新类,将相关字段和函数搬移到新类中。

12、如果如果为你提供服务的类,当前的方法函数不能满足你的要求,但你又无法修改这个类,那么你需要在调用该类服务的地方创建一个方法,利用参数传递,转化,处理,调用该服务类函数以补足该类的功能

13、扩展类。你需要服务类为你提供一些额外的功能,服务类本身又不能被修改。那么你应该新建一个类,将这些额外的函数包含进去。让这个新类成为服务类的扩展和出口。如线程池工具类

14、封装自定义字段。在类中,初始化某些变量。使用这些变量以get/set方法进行处理。(全局变量)

----------直接使用:适合那些fianl常量或者静态常量

----------间接使用:适合那些 “数值型” 频繁变化数据的。通过统一的输出端更适合理解与维护。比如打印为日志,补充数据,替换数据。

15、以对象代替数据值。如果某个数据项目需要与其他某些数据一起使用才有意义,那么应该将之与其他数据合并为对象。

16、将值对象替换成引用对象。你从一个类中产生了很多的相同的实例,希望将他们变成同一个对象,将这个值对象变成引用对象。

注释:共享(重复使用一个对象不丢弃,共享数据或共享访问)

--------对象:对象实例

--------对象引用:对象的引用,当一个对象需要被使用的时候,使用引用可以避免重复创建浪费空间,这也是声明符存在的意义

--------值对象:描述对象的一种可变状态,这种约束可以是单实例约束也可以是软件开发口头约束。这类对象多以包装类的形式存在。比如 “汽车对象”。可以通过设置私有值,不允许被外来改变。而成为一个固定的值对象。值对象可以起到既支持共享同一个实例引用以节省内存,又可以保证数据安全而不会产生别名问题。一般可以通过设置私有变量,同时关闭设置函数来保证对象不被外来操作修改。从而实现代码设计上的安全。

单例模式

-------引用对象:对象在系统中是类似 “资源” 一般的存在,引用对象体现了这个 “资源” 被共享的概念。即一个实例被重复引用。

注释:实例对象被重复存在是会占据和消耗资源的,相同的实例被重复创建是不合理的。

-------无状态对象:作为值对象中的一种,无论在什么时候他的结果都是一样的,不会因为使用的时序不同而不同。类似于工具类

和常量类。常规认识上是一个对象,不包含外部对象的引用,所有方法计算都只在方法中局部计算。或者变量已经不能被改变的对象。这类对象是线程安全的,无论什么时候计算也是稳定的结果。一般这类对象都是无实例的,成员变量私有化或final化不会再被外部改变。

注释:无状态对象不允许存在数据成员(局部方法里面的除外),不允许外部对象引用。

 

17、引用对象替换为值对象。存在着一个引用对象很小且不可改变,那么将之转化为值对象吧

18、去除不必要关联,两个类都存在着关联现在有某个关联已近失效,将之移除。

19、拒绝魔法数字。

20、封装字段。对于对象的某个属性pulibc字段,将之转换为private,并提供对应的 访问方法。

21、封装集合。某个集合被频繁使用,在这个类中对这个类集合进行封装,用get方式返回其只读副本,并创建移除函数。提高集合的灵活性。

22、简化表达式。对于if-else这一类条件分支,建议以断言的形式提炼出独立的函数。

23、合并条件表达式,如果你存在多个条件判断都得出相同的结果,将之合并成为一个大的条件表达式。如果过于复杂将条件进行提炼,但仍然保持一个表达式。

24、合并重复代码。如果代码的每个分支都执行了一个相同的条件,那么将这个条件迁移到表达式之外。

25、移除控制标记。在一系列布尔表达式中,某个变量带有“控制标记”(control flag)的作用。以break语句或return语句取代控制标记。

注释:比如说我拥有一个临时变量在不同条件下赋予不同的值,那么我将之重构,寻找统一的判断的方式,而后统一反馈或者不符合条件则退出。

比如 用swith的时候会产生很多个if ,那么我可以将条件转化为数组,而后进行for循环筛选,符合条件则返回,不符合条件则continue;

26、以多态取代条件表达式。尚未找到好的方式。

import org.springframework.util.StringUtils;

/**
 * @Author: CYQ
 * @Description: 抽象工厂
 * @Date: Created in 2019/9/10 22:46
 * @Modified By:
 */
public abstract class AbstarctFactory {


    protected abstract Car getCarByName(); //抽象类方法


    public Car getCarByName(String name){

        if (StringUtils.endsWithIgnoreCase(name,"Audi")){
            return new AudiFactory().getCarByName();
        }else  if (StringUtils.endsWithIgnoreCase(name,"Bmw")){
            return new BmwFactory().getCarByName();
        }else if (StringUtils.endsWithIgnoreCase(name,"benz")){
            return new BenzFactory().getCarByName();
        }else{
            return null;
        }

    };



}


如何引用呢?
=======================================创建默认子类继承该抽象类=================================

/**
 * @Author: CYQ
 * @Description: 默认工厂
 * @Date: Created in 2019/9/10 23:12
 * @Modified By:
 */
public class DefaultFactory  extends  AbstarctFactory{

    private AudiFactory  audiFactory=new AudiFactory();

    @Override
    protected Car getCarByName() {
        return audiFactory.getCarByName();
    }
}


使用区别在哪里?
===================================创建具体工厂,分场景使用==============================
1、具体工厂重写默认类方法。
注释:也就意味了拥有了两种场景。一种是默认生产模式,一种是具体工厂提供的创新模式。


/**
 * @Author: CYQ
 * @Description: 奥迪工厂
 * @Date: Created in 2019/9/10 22:14
 * @Modified By:
 */
public class AudiFactory extends AbstarctFactory {
    @Override
    public Car getCarByName() {
        return new Audi();
    }
}


=========================================================================================

/**
 * @Author: CYQ
 * @Description: 默认工厂
 * @Date: Created in 2019/9/10 23:13
 * @Modified By:
 */
public class DefaultFactoryTest {

    public static void main(String[] args){
        DefaultFactory defaultFactory=new DefaultFactory();
        System.out.println(defaultFactory.getCarByName());
        System.out.println(defaultFactory.getCarByName("Audi"));
    }
}

  注释1:多态存在的前提条件是 子类对父类存在着继承或实现的关系。一种是重载多态(正常重载),一种是父类引用指向子类对象。因为子类对象继承了父类,在编译和初始化的 时候也对父类进行了编译。因此父类对象是被默认创建好的。父类引用指向子类。如果子类不存这个方法则默认引用父类的方法,如果子类存在则会引用子类的方法(子类该方法已经进行了重写)。

 注释2:这里重写的定义,可以是原模原样的从父类复制到子类。不是一定要对方法进行改造。便已经是执行了覆盖。

27、简化函数调用。函数名应该显示这个函数的意义。

28、函数的参数超过3个,最好是打包发送

29、分离查询函数和修改函数,保证函数功能职责单一

30、聚合相似函数。某些函数大体相似,但是因为开发先后关系均为独立,将这些函数进行合并处理。

31、以明确函数代替参数。在函数里面,如果存在着一个函数,其返回的结取决于内部参数设置而返回不同的值。那么应该将参数提炼作为入参或者独立成为一个函数,然后调用函数获取数值。如果参数是配置参数,那么可以独立成为一个提供数据的函数。因为外部函数的不同入参而选择不同的行为或者运算方式。

注释:读取配置文件的函数以此获取数据。经过各种数据逻辑计算而获取到的结果。

32、保持对象完整性。如果获取对象的若干的属性,将他们作为某一次函数调用的参数,那么将该对象整个打包传送,以保持对象完整性。

33、尽量减少不必要的传递调用。A需要C的返回值,A通过调用B去调用C,从而获取数据这种是不合理的。

34、以对象取代参数。对于某些很频繁且同时出现的参数,以对象形式打包。后续使用以引用参数传递。

35、移除设置函数,如果一个属性在创建之初已经被被赋值且不再改变,移除其setter函数。

36、隐藏内部函数。如果某个函数没有被外类引用过,那么将之隐藏起来。

37、以工厂函数取代构造函数。在创建对象的时候不仅仅是简单的建构操作,而是将构造函数替换为工厂函数。

38、概括关系。

------如果超过两个字类存在相同字段,那么将该字段迁移到超类

------如果某些函数在子类中,产生完全相同的效果,那么将该函数迁移至超类。

------各个子类中的 构造函数本地内容几乎一样,将构造函数迁移至超类中,并在子类构造中进行调用

------超类中某个函数只为某个子类服务,那么将该函数迁移至该子类

------超类中某个字段只为某个子类服务,那么将函数迁移到该子类中

------类中某些特性只被某些实例使用,那么将这些特性提炼成一个子类,将上述特性 字段迁移到子类。(参考报文)

------多个子类中均存在某些特性,将这些特性提炼成一个新的超类,并将特性迁移进超类

------若干客户使用类接口的同一子集,或者两个类接口都存在相似,那么将接口提炼出一个新的接口,将特性进行迁移到接口中

------如果超类和子类没有什么大区别,将子类和超类合并吧

------子类中某些寒暑假具相同的操作顺序,但细节可能各有不同,将操作分别封装进不同的函数中,通过一个函数调用不同 的操作步骤函数,并将这个步骤函数提炼到超类中,成为模板函数。

================================================================================================

总结:

以上只是总结以及开发中重构和开发思想(仅供参考),但不是凡事都可以套到现实开发中。整体来说,以上为个模块,分别是:

--------->规范代码的用途(废话)

良好的代码规范和代码设计思路,可以使得你的开发越来越便捷,越来越高效,后续代码维护也极为方便。控制好测试与代码规范,初级BUG是完成可以避免的,这句话并不是开玩笑。

--------->不良规范的表现是怎么样的?(持续补充)

--------->常规应该怎么做?

================================================================================================

经验:在现实开发中,我们很少会去背诵这些规范,毕竟也不显示,大多数人都是依靠自己的经验来处理。无非就是一种感觉的问题,以下描述一些开发中需要游优化的经验:

1、参数过多

2、代码无读懂的注释

3、数据场景混乱,开发时一个参数搭配集中场景

4、魔法数值

5、数据库不规范字段。

6、函数过长

7、节点无注释。

 

 

 

 

1.尽量使用对象

2.保持类,方法职责清晰

3.数据传递通道直达

4.冗余字段,类,变量,重复代码删除。(如果你具备考虑全局的思维,对于两次需求周期内没有使用到的也不要进行注释,直接删除)

5.尽量提供输出口的方法,也就是对外输出,内部逻辑封闭修改

6.类和对象尽量纯粹

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值