• 设计模式(07)——设计原则(2)


    KISS原则

    Keep It Simple and Stupid 这个原则听起来比较简单,重点是理解什么样的代码是简单的,代码行数少就是简单的代码吗???还是说当程序的逻辑十分复杂不容易理解时就是一个复杂的代码呢???


    下面就让我们来看看怎么样判断简单。

    代码行数

    代码就不展示了,其实懂的都懂,代码行数是一定不能作为判断依据的,因为很多代码行数少的代码,其实是采用了一些高级语法特性的。如正则表达式、位运算符等。


    如果盲目的采用这些特性,会影响代码的可读性,因为这种运算法为了减少代码行数,会采用很多方式来规定一些特性,这些特性有时会不好理解。例如用位运算符来代替算数运算,这样虽然会提高代码性能和减少行数,但也不是 KISS 原则下的指导产物,其违反了代码的可读性。

    逻辑复杂

    那代码的逻辑复杂可以作为判断依据吗?其实也是懂的都懂,代码也不展示了(因为太复杂了,所以不展示了-v-),为什么逻辑复杂不能作为判断依据呢???


    因为有些代码他就是逻辑复杂的,如果不信的话,直接打开算法相关实现,找到一个看不懂的,那么其就是我们的目标了。


    因此如果没办法,在特定场景下,只能采用该算法的实现,那么使用这种复杂逻辑就不是违反 KISS 原则了,因为没办法。

    场景

    综上,我们该如何写出符合 KISS 原则的代码呢,具体来说,还是需要 结合业务发展和技术团队能力。


    在实际场景下,我们尽量做到以下几点就可以了。

    • 不使用同事可能不懂的语法和技术,例如 lambda、正则等(不过这些还好,例如 lambda 虽然有些时候部分地方还不让使用,但其实其早已不是一个新技术了,还不懂的话,这种情况可以考虑换个地方或者进行下部门培训了)
    • 不要重复造轮子,因为自己造的轮子在一定程度上肯定没有网上大家都用的好,比较容易出现问题,而这些问题可能在对应的轮子上已经被解决来(但自己学习的时候,该造还是要造)
    • 不要过度优化,炫技,例如为了提高性能和减少代码行数,使用大量的位运算符、复杂的条件表达式等,这些都是给机器看的,一般我们都不需要在这个性能上过分的优化,反而牺牲来代码的可读性

    YAGNI原则

    定义

    不要去设计当前用不到的功能,不要去写当前用不到的代码。


    该原则是作为一个指导思想来做的,其作用就是防止过度设计,但需要注意的是其是让你不做,但需要有可能要做的意识,提前留好拓展点,这样如果要做的时候,也可以快速跟上。
    **

    后续会有一篇文章,来专门讲解如何在软件设计中,防止过度设计,但对对应该优化,该留好优化点如何实现。

    DRY原则

    定义

    英语解释为:Dont repeat yourself,可以理解为不要写重复的代码,要做好代码的可复用性。但该规则跟 KISS 原则一样,听起来可能比较简单,但是在实际使用中,却要注重的一个原则。


    因为在该原则中,有一个很关键的点,什么样的代码是重复的代码,只是简单的代码一样就是违反该原则了吗?下面就让我们来根据以下几种场景来判断什么是重复的代码。

    实现逻辑重复

     public boolean validUsername(String username) {
            if (StrUtil.isEmpty(username)) {
                return false;
            }
            if (username.contains("77777")) {
                return false;
            }
            return true;
        }
    
        public boolean validNickname(String nickname) {
            if (StrUtil.isEmpty(nickname)) {
                return false;
            }
            if (nickname.contains("77777")) {
                return false;
            }
            return true;
        }
    

    我们来看一下,这一段代码是重复的吗?


    明显能看出,两个方法的执行逻辑是一模一样的,那么我们可以说其是重复的,而将其合为一个方法吗?


    答案是不行的,首先如果合成一个就违反了单一职责原则,一个方法做了多件事,此外,现在两个参数的校验逻辑是一样的,因此看着重复,后面如果 nickname 的校验逻辑改了呢?那就需要侵入式的修改代码,需要在所有使用该方法的代码中进行修改,依据 nickname 来特定的进行判断,从而违反了开闭原则。


    因此,实现逻辑重复,不能构成代码重复的条件。

    功能语义重复

        public boolean checkPasswordByRegex(String password) {
            String regex = "123456";
            boolean matches = Pattern.matches(regex, password);
            return matches;
        }
    
        public boolean checkPasswordByStr(String password) {
            boolean matches = StrUtil.equals(password, "123456");
            return matches;
        }
    


    我们来看一下,上述两段代码是否构成重复?


    答案是这两段代码是重复的代码,虽然这两段代码的实现逻辑不一致,代码编写也不一致,但其仍然违反了 DRY 原则,因为这两段代码所实现的点是一样的,下面我们来看一下这样重复的代码会带来什么隐患。


    这样的设计可能会导致以下问题,

    1. 当一个不知情的人看到这两段代码完成的任务是一样的,但采用的解决方式却是不一样的,则会想其的设计深意,以及不知道该用哪一个?
    2. 当函数的实现逻辑要改的时候,可能会导致修改了其中一个,而忘记修改另一个,这样则会造成逻辑的不一致。

    代码执行重复

        // 代码执行重复
        public boolean validContainsA(String temp) {
            if (StrUtil.isNotEmpty(temp) && temp.contains("A")) {
                return true;
            }
            return false;
        }
    
        public boolean validTemp(String temp) {
            if (StrUtil.isNotEmpty(temp) && temp.contains("A")) {
                return true;
            }
            return validContainsA(temp);
        }
    

    上述代码因为举的例子比较简单,应该能很简单的看出有一段代码被执行了两次,那么这样的设计违反了 DRY 原则吗?


    我们认为其也是违反的,这里放的只是一个简单的逻辑判断,所以看不出来什么,如果这里是放了一个耗时操作呢,例如读取数据库、文件等。那么进行重复的执行,则会影响整个程序的对外性能。

    总结

    因此,判断如何一个代码是否是重复的,需要结合具体场景来做判断,在这里,我们可以看到代码实现方式一样不能作为判断依据,因此其实现的语义是不同的,这就是功能语义的判断范畴,而对于重复执行,我们在代码里需要做到尽量避免,因为如果重复执行费时操作,则会导致代码整体对外的性能下降。

    迪米特原则

    定义

    迪米特原则是用来指导设计高内聚、低耦合代码的原则,因此我们先看一下什么是高内聚、低耦合。

    • 高内聚:相近的功能放到一个类或模块中,不相近的功能不要放到一个类中,暗合了单一职责原则;
    • 低耦合:类和类之间的依赖关系清晰简洁,即使有依赖,也要做到其中一个修改,依赖或被依赖的少修改。


    看到想要完成的目标,现在再来看一下什么是迪米特原则。


    其概念是:每个类或模块只需要了解与他关系密切即紧密关联的类或模块。再换句话说:

    • 不该有依赖关系的不要有依赖;
    • 有依赖关系,只依赖必要的接口。

  • 相关阅读:
    JAVA动态添加枚举值
    maven仓库配置
    AWS S3 上传下载文件
    golang http client的MaxConnsPerHost限制
    redis cli的特殊用法
    go调度: 第三部分-并发
    tcmalloc的memory heap profiler
    【流数据处理】MySql/PG/Oracle+Kafka+Flink(CDC捕获) 部署及实时计算
    【概念】详解MapReduce原理
    一次失败的创业经历
  • 原文地址:https://www.cnblogs.com/JRookie/p/14089876.html
Copyright © 2020-2023  润新知