必须要掌握的工程师思维:抽象、分层

必须要掌握的工程师思维:抽象、分层

迄今为止,我在CSDN训练营学到的最重要的东西,就是工程师思维,今天把它分享给大家

所谓工程师思维,一是抽象,二是分层。我把它理解为以下:

  • 抽象:实现某个功能的“块”代码(可以理解为函数)
  • 分层:每一层只需要关注本层的内容,所实现的功能,而不需要关注所调用的函数(子代码块)是怎么实现的。

我们拿建(布置)房子来打比方,“块”代码就是我们的一个个实现某个功能的对象(大如客厅、厨房等,小如一支笔、一瓶水,都可以是这个对象),而最终要实现的程序就是我们所要布置的房子。

那该怎么建房子呢?

  1. 首先当然是从做好一块砖开始(在程序里,就是把程序所要实现的功能先逐步分解,直到分解到最小的模块,不可再分为止)。
  2. 然后是用很多个这样的砖来实现某个特定的功能,比如做一面墙、一条梁、一块台阶等(在程序里,就是用第1步所构造的代码块,根据不同的要求,来构建功能不同的、更大的代码块)。此时不用管砖是如何被造出来的(即第1步所构造的代码块是如何实现的)。
  3. …………
  4. …………
  5. ………… 然后是功能更大的代码块,越来越大,
  6. ……
  7. …… 一步一步
  8. 直到最终实现我们所需要的功能,做出整个程序。

一个实例:
问题:假设我们要用C语言,在屏幕上输出矩形、空心矩形、等腰三角形、菱形、“回”字,该如何设计你的程序?

对于这个问题,我们先来看一个不好的案例:

#include <stdio.h>
  
int main()
{
    int i,j;
    for(i=0;i<4;i++){
        for(j=0;j<4;j++){
            printf("*");
            if(j==3){printf("\n");}
        }
    }

    printf("\n");

    for(i=0;i<4;i++){
        for(j=0;j<4;j++){
            if((j==1&&i==1)||(j==2&&i==1)||(j==1&&i==2)||(j==2&&i==2)){printf(" ");}else{printf("*");}
            if(j==3){printf("\n");}
        }
    }

    printf("\n");
//以下就是直接用拼接图形的方法了,实在不知道要怎么写,太麻烦了
    for(i=0;i<3;i++){
        if(i==0){
            printf("  *  \n");
        }else if(i==1){
            printf(" *** \n");
        }else{
            printf("*****\n");
        }

    }

    printf("\n");

    for(i=0;i<3;i++){
        if(i==0){
            printf("  *  \n");
        }else if(i==1){
            printf(" * * \n");
        }else{
            printf("*****\n");
        }
    }

    printf("\n");

    for(i=0;i<5;i++){
        if(i==0||i==4){
            printf("  *  \n");
        }else if(i==1||i==3){
            printf(" * * \n");
        }else{
            printf("*   *\n");
        }
    }

    printf("\n");

    for(i=0;i<5;i++){
        if(i==0||i==4){
            printf("******* \n");
        }else if(i==1||i==3){
            printf("* *** *\n");
        }else{
            printf("* * * *\n");
        }
    }
}

怎么样?开头的几个for循环是不是看得头都晕了?这样的代码可读性很差(你根本就无法一下子看懂),可维护性也很差(万一中间某个循环里出了问题,你得一层一层的去找,是不是很累?)。而且当我们在遇到大项目的时候,面对的是成千上万行的代码,如果还按照以前我们的经验来写程序,那到最后很容易就会让代码失控——你也不知道你写的是什么玩意儿,可能调一调程序正常了,然后过了某一段时间突然又崩溃了。

下面我们按抽象、分层的思想来解决一下这个问题。

程序设计思维导图
下面我们来看一下代码:

#include <stdio.h>
  
//输出一个"*",或其他任意符号
int p_one(char c)
{
    printf("%c",c);
    return 0;
}

//输出一行n个的"*",或其他任意一行符号
int p_oneline(int n,char c)
{
    int i;
    for(i=0;i<n;i++){
        p_one(c);
    }
    return 0;
}

//输出一个m行n列的矩形
int p_rectangle(int m,int n,char c)
{
    int i;
    for(i=0;i<m;i++){
        p_oneline(n,c);
        printf("\n");
    }
    return 0;
}

//输出一个m行n列的空心矩形
int p_hollow_rectangle(int m,int n,char c)
{
    int i;
    p_oneline(n,c);    //先输出空心矩形的第一行
    printf("\n");
    for(i=0;i<m-2;i++){    //中间输出矩形的空心的部分,一共m-2行
        p_one(c);
        p_oneline(n-2,' ');
        p_one(c);
        printf("\n");
    }
    p_oneline(n,c);    //最后输出空心矩形的最后一行
    printf("\n");
    return 0;
}

//输出一个底为m,高为n的等腰三角形
int p_triangle(int m,int n,char c)
{
    int i;
    for(i=1;i<=n;i++){
        p_oneline( (m-(2*i-1))/2 ,' ');    //一行的开头先输出((m-(2i-1))/2)个空格
        p_oneline(2*i-1,c);    //中间输出(2i-1)个'*'
        p_oneline( (m-(2*i-1))/2 ,' ');    //一行的末尾也要输出((m-(2i-1))/2)个空格
        printf("\n");
    }
    return 0;
}


//输出菱形的上部分长为m,高为n的三角形
int p_up_triangle_for_diamond(int m,int n,char c)
{
    int i;
    for(i=1;i<=n;i++){
        p_oneline( (m-(2*i-1))/2+1 ,' ');    //一行的开头先输出((m-(2i-1))/2+1)个空格
        p_oneline(2*i-1,c);    //中间输出(2i-1)个'*'
        p_oneline( (m-(2*i-1))/2+1 ,' ');    //一行的末尾也要输出((m-(2i-1))/2+1)个空格
        printf("\n");
    }
    return 0;
}


//输出菱形的下部分长为m,高为n的三角形
int p_down_triangle_for_diamond(int m,int n,char c)
{
    int i;
    for(i=n;i>=1;i--){
        p_oneline( (m-(2*i-1))/2+1 ,' ');    //一行的开头先输出((m-(2i-1))/2+1)个空格
        p_oneline(2*i-1,c);    //中间输出(2i-1)个'*'
        p_oneline( (m-(2*i-1))/2+1 ,' ');    //一行的末尾也要输出((m-(2i-1))/2+1)个空格
        printf("\n");
    }
    printf("\n");
    return 0;
}

//输出一个水平对角线为m,竖直对角线为n的菱形
int p_diamond(int m,int n,char c)
{
    int i;
    p_up_triangle_for_diamond(m-2,n/2,c);    //输出菱形的上半部分三角形
    p_oneline(m,c);    //输出菱形的水平对角线
    printf("\n");
    p_down_triangle_for_diamond(m-2,n/2,c);    //输出菱形的下半部分三角形
    return 0;
}

//输出“回”字的对称轴相邻的行
int p_AxisOfSymmentry_OfHui_neighbor(char c)
{
    p_one(c);
    p_one(' ');
    p_oneline(3,c);
    p_one(' ');
    p_one(c);
    return 0;
}

//输出“回”字的对称轴
int p_AxisOfSymmentry_OfHui(char c)
{
    int i;
    for(i=0;i<7;i++){
        if(i%2==0){
            p_one(c);
        }else{
            p_one(' ');
        }
    }
    return 0;
}

//输出一个长为7,宽为4的“回”字
int p_hui(char c)
{
    p_oneline(7,c);    //输出最上面一行的“横”
    printf("\n");
    p_AxisOfSymmentry_OfHui_neighbor(c);    //输出“回”字对称轴的相邻行
    printf("\n");
    p_AxisOfSymmentry_OfHui(c);    //输出“回”字的对称轴
    printf("\n");
    p_AxisOfSymmentry_OfHui_neighbor(c);    //输出“回”字对称轴的相邻行
    printf("\n");
    p_oneline(7,c);    //输出最下面一行的“横”
    printf("\n");
    return 0;
}

int main()
{
    p_rectangle(4,3,'*');
    printf("\n");
    p_hollow_rectangle(5,5,'x');
    printf("\n");
    p_triangle(5,3,'#');
    printf("\n");
    p_diamond(5,5,'$');
    p_hui('@');
    return 0;
}

怎么样?是不是清晰了许多?至少不用再一个循环一个循环里去找了。而且我当初在写这段代码的时候,最后调试几乎一次性就成功了,对比之前那段代码,调了好多遍才出结果。

从中我们可以看出抽象、分层这种思想的精髓,只要你最低层的代码写对了(那块砖做好了),以后就不需要再管这段代码了,它不可能出错。错误只可能出现在你调用的地方。

最后来看一下我们的成果:
成果

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值