2022春季学期高级软件工程总结

caosy233 2022-07-10 22:28:46

一、工欲善其事必先利其器

1、 VSCode快捷键

ctrl/win + O —— 打开文件夹
ctrl/win + N —— 新建文件
ctrl/win + W —— 关闭文件
ctrl/win + K + W —— 关闭所有文件
ctrl/win + K + U —— 关闭已保存的文件
ctrl/win + S —— 保存文件
ctrl + / —— 单行注释
ctrl + shift + A —— 块注释
ctrl + shift + E —— 资源管理器
ctrl + shift + F —— 跨文件搜索
ctrl + shift + G —— 源代码管理
ctrl + shift + D —— 启动与调试
ctrl + shift + X —— 管理扩展
ctrl + shift + M —— 显示错误和警告
ctrl + shift + P —— 查找并运行所有命令
ctrl + ` —— 切换集成终端

2、 Git


(1)操作逻辑

 

(2)命令
git init —— 在目录下创建版本库
git status —— 查看当前工作区(workspace)状态
git add file —— 将文件添加至暂存区(index)
git commit -m "commit log" —— 将暂存区(index)里的文件提交至仓库
git log —— 查看HEAD前提交的记录,便于回到过去
git reflog —— 查看HEAD之后提交的记录,便于回到未来
git reset [--soft | --mixed | --hard] [HEAD] —— 回退到某次提交的版本
--mixed 默认 重置暂存区和上次保持一致,工作区文件内容不变
--soft 回退到某个版本
--hard 撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删
除之前的所有信息提交
git fetch —— 将远程库下载到本地库
git clone url —— clone远程库并在本地创建版本库
git merge —— 合并两个或多个开发历史记录
git pull —— 从其他存储库或分支抓取并合并到当前存储库的当前分支 (= git fetch + merge)
git push —— 将本地库相关数据对象更新至远程库
git checkout  —— 切换分支
git checkout -b  —— 创建并切换分支
git branch —— 查看分支
git branch  —— 创建分支(并不切换)
git rebase —— 另一个分支基础之上重新应用,用于把一个分支的修改合并到当前分支。

 

(3)git clone/fetch/pull区别
clone无需初始化本地仓库,fetch和pull则需要
clone下来的项目可直接push,fetch、pull的项目则需要git remote add后才能push


(4)git merge和git merge -no-ff的区别
git merge –no-ff 可以保存你之前的分支历史。能够更好的查看 merge历史,以及branch 状态。
git merge 则不会显示 feature,只保留单条分支记录。


3、 正则表达式

(1)表达式

| —— 或

. —— 匹配任意一个字符

+ —— 匹配出现一次或多次的字符(前一个字符)

* —— 匹配出现零次或多次的字符(前一个字符)

? —— 匹配出现零次或一次的字符(前一个字符)

{下限,上限} —— 匹配出现上限到下限次的字符

[字符] —— 匹配一组希望的字符

- —— 定义要匹配的字符范围,如[a-z]匹配从a-z的字符

^ —— 定义不要匹配的字符,如[^aeiou]匹配元音以外的字符

^ —— 表示字符串开头

$ —— 表示字符串结尾

\w —— 即[A-Za-z0-9_]

\W —— 即[^A-Za-z0-9_]

\d —— 即[0-9]
\D —— 即[^0-9]

(需要捕获的内容) —— 即捕获组

exp. 匹配42 42 42 —— (\d+)\s\1\s\1 其中\1即代表捕获组(\d+)


(2)贪婪匹配&懒惰匹配
默认greedy即贪婪匹配找到符合正则表达式模式的字符串的最长可能部分,并将其作为匹配返回。
可用?开启lazy即找到符合正则表达式模式的字符串的最小可能部分。
exp: titanic
t[a-z]*i -> titani
t[a-z]*?i ->ti


二、代码中的软件工程

1、 编写高质量代码
控制结构、数据结构、不断重构、错误处理,性能代价


2、 模块化的基本原理
各部分相对独立,独立设计与开发,定位bug,便于维护


3、本地化外部接口是什么含义
不要和陌生人说话原则
本质上代理模式
不直接调用外部api,而是调用本地的外部接口,该接口再去调用外部接口
降低耦合度。


4、 接口的基本概念
定义了提供的服务、如何访问服务


5、接口的5个基本要素
目的
前置条件
协议规范(如http协议,png图片格式,json数据格式定义etc..)
后置条件,(结果)
质量属性(如响应时间)


6、耦合方式
公共耦合:共享数据区或者变量名。
数据耦合:显式的调用传递 基本数据类型。
标记耦合显式的调用传递复杂的数据结构(结构化数据)
数据耦合<标记耦合<公共耦合


7、通用接口定义的基本方法
参数化上下文,通过参数来传递信息,不依赖上下文环境
移除前置条件   如移除参数个数限制
简化后置条件 如简化需求(结果),求某数组前n位和求数组总和


8、可重入函数与线程安全
可重入的函数可能是线程安全的也可能不是线程安全的;在多个线程中并发使用时是线程安全的,但不同的可重入函数(共享全局变量及静态变量)在多个线程中并发使用时会有线程安全问题 不可重入的函数一定不是线程安全的


三、从需求分析到软件设计

1、需求类型
功能性需求:根据需要的活动描述需要的行为 质量需求或非功能需求:描述软件必须具备的一些质量特征 设计约束:设计决策,如平台或接口组件的选择 过程约束:对可用于构建系统的技术或资源的限制


2、高质量需求的特点
需求可测试
解决冲突:将需求按优先级排序
正确 一致性 无二义性 可行 相关 可追溯 完整


3、需求分析的两类基本方法    

原型化方法(Prototyping)和建模的方法(Modeling)是整理需求的两类基本方法。

原型化方法:便于整理用户接口方式(UI,User Interface),比如界面布局和交互操作过程。
建模的方法:可以快速给出有关事件发生顺序或活动同步约束的问题,能够在逻辑上形成模型来整顿繁杂的需求细节。


4、用例的概念
逻辑整理抽象出的业务过程,完成相应业务的一系列活动


5、用例满足的四个必要条件
是一个业务过程
由某参与者触发
为某参与者完成相应需求
由某参与者结束


6、用例的三个抽象层级
抽象用例:动名词短语,用来精简的指明某用例
高层用例:给用例范围划定边界(开始、结束)
扩展用例:所有交互步骤的详细描述


7、用例建模的步骤
需求中找出用例,往往是抽象用例
描述用例开始与结束的状态,高层用例
按照系统分类,描述用例与用例,用例与参与者的上下文关系,画出用例图
描述用例与参与者详细的交互步骤,(扩展用例)
1到3为计划阶段,4是增量实现


8、准确提取用例的基本方法
从需求寻找相应业务领域的动名词短语等
判断是否满足4个必要条件
从需求中识别出参与者、系统等


9、统一过程的核心要义
用力驱动、架构为中心、增量且迭代的过程


10、敏捷统一过程的四个关键步骤
确定需求 通过用例的方式来满足这些需求 分配这些用例到各增量阶段 具体完成各增量阶段所计划的任务

 

四、软件科学基础概论

1、软件中的一些特殊机制

(1)回调函数
回调函数就是一个通过函数指针调用的函数。把函数的指针(地址)作为参数传递给另一个函数,当这个指针调用其所指向的函数时,就称这是回调函数。回调函数不是该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

int SearchCondition(tLinkTableNode * pLinkTableNode, void* args)
{
    tDataNode * pNode = (tDataNode *)pLinkTableNode;
    char* cmd = (char*)args;
    if(strcmp(pNode->cmd, cmd) == 0)
    {
        return  SUCCESS;
    }
    return FAILURE;
}

tDataNode* FindCmd(tLinkTable * head, char * cmd)
{
    return  (tDataNode*)SearchLinkTableNode(head,SearchCondition,(void*)cmd);
}

tLinkTableNode * SearchLinkTableNode(tLinkTable *pLinkTable, int Conditon(tLinkTableNode * pNode, void* agrs), void* agrs)
{
    if(pLinkTable == NULL || Conditon == NULL)
    {
        return NULL;
    }
    tLinkTableNode * pNode = pLinkTable->pHead;
    while(pNode)
    {
        if(Conditon(pNode, agrs) == SUCCESS)
        {
            return pNode;
        }
        pNode = pNode->pNext;
    }
    return NULL;
 }

 

(2)继承和组合
继承可以重用代码,但是破坏了代码的封装特性,增加了父类与子类之间的代码模块耦合,因此我们需要避免使用继承,在大多数情况下,应该使用对象组合替代继承来实现相同的目标

 

(3)多态
允许将不同的子类类型的对象动态赋值给父类类型的变量,通过父类的变量调用方法在执行时实际执行的可能是不同的子类对象方法,因而表现出不同的执行效果

 

(4)闭包
闭包是变量作用域的一种特殊情形,一般用在将函数作为返回值时,该函数执行所需的上下文环境也作为返回的函数对象的一部分,这样该函数对象就是一个闭包 函数和对其周围状态的引用捆绑在一起构成闭包,在JavaScript中,每当函数被创建,就会在函数生成时生成闭包

 

(5)异步调用
Promise对象实际上是对回调函数机制的封装,也就是通过then方法定义的函数与resolve/reject函数绑定,简化了回调函数传入的接口实现,在逻辑上也更加通顺,看起来像是个同步接口

 

(6)匿名函数
lamda函数是函数式编程中的高阶函数,在我们常见的命令式编程语言中常常以匿名函数的形式出现,比如无参数的代码块{ code },有参数的匿名函数往往会使用箭头函数 { x => code };


2、常用设计模式


观察者模式

//观察者模式中的被观察者的核心部分
var Dep = function(){
    this.subs = {};
};
Dep.prototype.addSub = function(target){
    if(!this.subs[target.uid]) {
        //防止重复添加
        this.subs[target.uid] = target;
    }
};
Dep.prototype.notify = function(newVal){
    for(var uid in this.subs){
        this.subs[uid].update(newVal);
    }
};
Dep.target = null;

//创建Watcher,观察者模式中的观察者
var Watcher = function(exp, vm, cb){
    this.exp = exp; // 占位符/表达式的一个成员
    this.cb = cb; //更新视图的回调函数
    this.vm = vm; //ViewModel
    this.value = null;
    this.getter = parseExpression(exp).get;
    this.update();
};

Watcher.prototype = {
    get : function(){
        Dep.target = this;
        var value = this.getter?this.getter(this.vm):'';
        Dep.target = null;
        return value;
    },
    update :function(){
        var newVal = this.get();
        if(this.value != newVal){
            this.cb && this.cb(newVal, this.value);
            this.value = newVal;
        }
    }
};

Observer.prototype.defineReactive = function(data, key, value){
    var dep = new Dep();
    Object.defineProperty(data, key ,{
        enumerable:true,
        configurable:false,
        get:function(){
            if(Dep.target){
                //添加观察者
                dep.addSub(Dep.target);
            }
            return value;
        },
        set:function(newVal){
            if(newVal == value){
                return;
            }
            //data[key] = newVal;//死循环!赋值还会调用set方法
            value = newVal;//为什么可以这样修改?闭包依赖的外部变量
            //遍历newVal
            this.transform(newVal);
            //发送更新通知给观察者
            dep.notify(newVal);
        }
    });

    //递归处理
    this.transform(value);
};
Observer.prototype.transform = function(data){
    for(var key in data){
        this.defineReactive(data,key,data[key]);
    }
};


3、设计模式的原则

开闭原则:扩展开放,修改关闭
Liskov替换原则:继承必须保持超类的性质在子类中仍然成立
依赖倒置原则:高层模块不应该依赖低层模块,俩者都应该依赖其抽象,抽象不依赖细节,细节依赖抽象,核心思想是:面向接口编程,而不是面向实现编程
单一职责原则:一个类应该有且仅有一个引起其变化的原因,否则应将其拆分
迪米特法则:如果俩软件实体无需直接通信,则不应当发生直接调用,应通过第三方转发调用
合成复用原则:它要求在软件复用时,要尽量先使用组合或者聚合关系来实现,其次才考虑使用继承关系来实现。如果要使用继承关系,则必须严格遵循Liskov替换原则

4、软件架构

(1)MVC
Model代表一个存取数据的对象及其数据模型
View代表模型包含的数据的表达方式,一般表达为可视化的界面接口
Controller作用于模型和视图上,控制数据流向模型对象,并在数据变化时更新视图。控制器可以使视图与模型分离开解耦合
(2)MVVM
把Model用纯JavaScript对象表示,View负责显示,两者做到了最大限度的分离。把Model和View关联起来的就是ViewModel。ViewModel负责把Model的数据同步到View显示出来,还负责把View的修改同步回Model
(3)MVC架构为什么更灵活以及MVVM架构为什么更智能
MVC: 为了包容需求上的变化而导致的用户界面的修改不会影响软件的核心功能代码,采用将模型(Model)、视图(View)和控制器(Controller)相分离的思想
MVVM: View和Model之间没有联系,通过ViewModel进行交互,而且Model和ViewModel之间的交互是双向的,因此视图的数据的变化会同时修改数据源,而数据源数据的变化也会立即反应到View上


5、软件架构的视图

分解视图:用软件模块构建出系统结构,通过不同抽象层级的模块形成层次化的结构
依赖视图:展现了软件模块间的依赖关系,便于找到独立的模块
泛化视图:展现了一般化或具体化的关系,典型应用是面向对象分析和设计方法中类之间的继承关系
执行视图:展示了系统运行时的时序特点,比如流程图、时序图等 执行实体可以最终分解到软件的基本元素和软件的基本结构,因而与软件代码具有比较直接的映射关系。在设计与实现过程中,我们一般将执行视图转换为伪代码之后,再进一步转换为实现代码
实现视图:描述软件架构与源文件之间的映射关系。有助于码农在海量源代码文件中找到具体的某个软件单元的实现。实现视图与软件架构的静态结构之间映射关系越是对应的一致性高,越有利于软件的维护
部署视图:是将执行实体和计算机资源建立映射关系 部署视图有助于设计人员分析一个设计的质量属性,比如软件处理网络高并发的能力、软件对处理器的计算需求等
工作分配视图:将系统分解成可独立完成的工作任务,以便分配给各项目团队和成员


五、软件危机和软件过程

1、没有银弹

软件工程专家们所找到的各种方法解决不了软件概念结构的复杂性,无法达成软件概念的完整性和一致性,无法从根本上解决软件危机带来的困境

2、瀑布模型

瀑布模型是一个过程活动的顺序结构,没有任何迭代。瀑布模型不能为处理开发过程中的变更提供任何指导意义,因为瀑布模型假定需求不会发生任何变化。

3、v模型

在瀑布模型基础上将需求分析和接受度测试、系统设计和系统测试、详细设计和单元测试结合起来,最后是产品,提高过程活动的内聚度。V模型就是开始一个特定过程活动和评估该特定过程活动成对出现,从而便于软件开发过程的组织和管理。

4、敏捷宣言的核心思想

个体和互动高于流程和工具 工作的软件高于详尽的文档 客户合作高于合同谈判 响应变化高于遵循计划。

 

参考资料

代码中的软件工程: 软件工程: 《代码中的软件工程》一书的配套ppt和源代码

作者:104

 

...全文
72 1 打赏 收藏 举报
写回复
1 条回复
切换为时间正序
请发表友善的回复…
发表回复

ctrl/win + O —— 打开文件夹


上了这门课, 我感觉收获应该远远大于收集了这些快捷键吧?

  • 打赏
  • 举报
回复
发帖
代码中的软件工程

395

社区成员

软件工程教学新范式,强化专项技能训练+基于项目的学习PBL。Git仓库:https://gitee.com/mengning997/se
软件工程 高校
社区管理员
  • 码农孟宁
加入社区
帖子事件
编辑了帖子 (查看)
2022-07-10 22:30
编辑了帖子 (查看)
2022-07-10 22:29
创建了帖子
2022-07-10 22:28