问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

《Code Aesthetic》教你简化代码

创作时间:
作者:
@小白创作中心

《Code Aesthetic》教你简化代码

引用
CSDN
1.
https://blog.csdn.net/dadianjishiqi/article/details/144792243

《Code Aesthetic》是一系列关于代码美学和编程最佳实践的视频教程。本文总结了其中一些实用的建议,包括变量命名、代码复用、依赖注入、注释使用、嵌套消除等多个方面,帮助开发者写出更优雅、更易读的代码。

1. 命名方式(Naming Patterns)

如果不是特殊需要,变量名不要使用单个字母或者缩写。以前提倡缩写是为了节省打字时间,现在编辑器都有变量提示功能根本不需要缩写,习惯缩写会让你连前几天写的的代码都看不懂了!!更不要说给别人看。

为了提高代码可读性,应该在变量名中加入一些有用的信息,比如变量类型(如果是动态类型的语言如python、JS就很有必要,静态类型的语言如C++、Java就没必要)、数据类型(数组维度等)、时间单位等,根据不同情况来选择不同的命名元素

# 改进前
add_numbers = [1,2,3]
renderInterval = 0.1
# 改进后
add_numbers_list = [1,2,3]
renderIntervalSeconds = 0.1  

变量名不要加入一些无用(抽象)的词,比如Base、Simple等,这些词汇对理解代码毫无作用。

2. 代码复用

继承(inherit)、组合(composition)都是为了代码复用,但是“组合优于继承”

继承的本质就是将父类复制给子类,然后在这基础上再添加新的内容或重写原有内容。但很多时候子类只需要父类中的一部分内容,这样的继承会产生大量冗余的脏复制(脏复制 dirty duplication)

组合的方式,是在需要使用共用代码的时候才调用它,这样可以将私有和公用的代码分离。

组合的方式还可以再优化,直接在类里面写一个变量来接受这个复用代码,这是就变成了依赖注入。

// 继承方式复用代码
class Image {
    size image_size
    save()
    load()
    crop()
    resize()
}
class png:Image{
    crop()
}
class jpg:Image{
    resize()
}
// 组合方式复用代码
class Image{
    size image_size
    save()
    load()
}
class png{
    crop(Image image)
}
class jpg{
    resize(Image image)
}
// 依赖注入复用代码
class Image{
    size image_size
    save()
    load()
}
class png{
    Image image;
    png(Image image) {
        this.image = image;        
    }
    crop()
}
class jpg{
    Image image;
    png(Image image) {
        this.image = image;        
    }
    resize()
}
  

依赖注入(Dependency Injection)就是把要用到的东西(依赖)以接口的形式作为参数传进来(注入)

// 接口
ImageFile file{
    save()
    load()
}
class ImageApp {
    Image image = new Image();
    ImageFile file;                // 依赖
    ImageApp(ImageFile file){
        this.file = file;          // 依赖注入
        this.file.load(image);
    }
    show(){
        // show the image
    }
}
void main() {
    my_file = ImageFile()
    my_image_app = ImageApp(my_file)
    my_image_app.show()
}  

4. 抽象与耦合

代码的抽象(Abstraction)会带来耦合(coupling),高耦合度会导致代码难以修改,是很常见的现象,不要过分追求两全其美的代码,复用和耦合冲突时,根据实际需要来权衡。

5. 不写注释(Don't write comments)

如果一段代码需要写注释,说明你的代码写的不够清楚,还可以优化。写注释是好习惯,但是为了改代码的时候不用再麻烦地去改一遍注释,还是有必要精简一下注释的。另外,虽然我们有能力去检查代码错误,但是很难去检测注释错误(不过现在的AI可以)。

例子1:可以用注释来解释数字5的意义,但是更好的做法是定义一个变量来表示它。

#A status of 5 signals message sent
if status == 5
    message.markSent()
# 不写注释,用变量解释
MESSAGE_SENT = 5
if status == MESSAGE_SENT
    message.markSent()  

例子2:用注释解释多个判断条件,这时可以使用多个变量来代替,也可以把判断条件写成函数。将条件写成变量不仅可以省略注释,还使得条件可以复用。

# 优化前
# You can update a message IF 
# the current user is the author of the message and the message was delivered
# less than 5 minutes ago OR if the current user is an administrator
# You can also edit the message if the message wasn't delivered yet
if (message.user.id == current_user.id and(message.delivered_time() is None 
    or (datetime.now()-message.delivered_time()).seconds < 300))
    or current user.type == User.Administrator):
    message.update_text(text);
# 优化1
# 使用变量代替条件
FIVE_MINUTES = 5*60
user is author = message.user,id == current user.id
is_recent = message.delivered_time() is None or (datetime.now()- message.delivered_time()).seconds < FIVE_MINUTES
user_is_admin = current_user.type == User.Administrator
if(user_is_author and is_recent) or user_is_admin:
    message.update_text(text);
# 优化2
# 写成函数形式
def can_edit_message(current user, message):
    FIVE_MINUTES=5*60
    user_is_author = message.user,id == current_user.id
    is_recent = message.delivered_time()is None or (datetime.now() - message.delivered_time()).seconds < FIVE_MINUTES
    user_is_admin = current_user.type == User.Administrator
    return (user_is_author and is_recent) or user_is_admin
if can_edit_message(current_user, message):
    message.update_text(text);  

如果你代码写的好,代码比注释更有解释能力,直接看代码就能读懂,注释就没有必要了。不过多数情况下注释是很有必要的,比如为了性能优化写的很晦涩、或者使用了某些数学公式、代码的来源。

6. 不写嵌套(never nesting)

多层嵌套的代码难以阅读,有两种手段来消除嵌套:

第一种方法是把一部分代码提炼成一个单独的函数,但是会增加调用函数的开销(不过一般情况下这种开销不大)。另一方法是是调整条件的顺序,使函数尽快返回。

如下面把第二个分支写到前面,第一分支就可以从else解放出来。这种形式就是验证守护(validation gatekeeping),把执行函数的要求写在函数功能的前面。

// 优化前
int calculate(int bottom,int top)
{
    if(top >= bottom) 
    {
        int sum = 0;
        for (int number =bottom;number <= top;number++) 
![](https://wy-static.wenxiaobai.com/chat-rag-image/9920376236993221858)
        {
            sum += filterNumber(number);
        }        
        return sum;
    }
    else 
    {
        return 0;
    }
}
// 优化后
int calculate(int bottom,int top)
{
    // 验证守护
    if(top < bottom) 
    {
        return 0;
    }
    int sum = 0;
    for (int number =bottom;number <= top;number++) 
    {
        sum += filterNumber(number);
    }        
    return sum;
}  

7. 不要过早优化(Permature Optimization)

你认为可以更快的做法实际上可能更慢(过早的断定优化方案),要以实际测量来选择优化方案。

例子1:C++中的++i 比 i++要快一些,因为i++需要复制一遍值给当下的代码,执行完代码再在原来的变量上加1。既然如此,为什么不能只用++i呢?作者查看了两者的汇编代码,i++确实比++i多了几行代码,但是当开启优化时,两者代码是一样的。这时候只能实际跑一下来测试时间,最后作者发现i++确实慢了。

例子2:查询某个用户的场景下,使用集合(set)即散列来代替列表能够更快地查找,但是当用户数量少数,对比实际测量得到的时间,集合会比列表慢,这是因为列表在内存中是连续的,而集合可能会在内存中四处分配,降低了缓存命中率。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号