名词解释 #
软件工程 #
- 软件工程是 应用系统的、规范的、可量化的方法来开发、运行和维护软件,即将工程应用到软件
- 对以上各种方法的研究
抽象与分解 #
- 分解是横向将系统分割为几个相对简单的子系统以及子系统之间的关系,分解之后每次只需关注经过抽象的相对简单的子系统以及相互间的关系,从而降低了复杂度
- 抽象是在纵向上聚焦各自系统的接口,抽象可以分离接口与实现过程,让人更好的关注系统本质,减低复杂度
- 分解和抽象是一起使用的,可以将系统分解为子系统,又通过抽象分离接口与实现
描述软件体系结构的分层风格 #
根据不同的抽象层次将系统组织为层次式结构,每个层次被建立为一个部件,不同的部件之间通常用程序调用的方式进行连接
- 优点:设计机制清晰易于理解。支持并行开发。更好的可复用性和内部可修改性
- 缺点:交互协议难以修改。性能损失。难以确定层次数量和粒度。
描述软件体系结构的面向对象风格 #
该风格将系统组织为多个独立的对象,每个对象封装其内部的数据,并基于数据对外提供服务,不同的对象之间通过协作机制共同完成系统任务。
- 优点:内部实现的可修改性。易开发、易理解、易服用的结构组织。
- 缺点:无法消除接口的耦合。印记耦合。面向对象编程中的副作用。
重构 #
修改软件系统的严禁方法,在不改变代码外部表现的情况下改变其内部结构。重构发生在新功能增加完成后,用于消除新功能带来的负面影响
软件需求 #
- 需求就是用户的一种期望,用户为了解决问题或达到某些目标所需要具备的条件和能力。
- 系统或系统部件为了满足合同、标准、规范或其他正式文档所规定的要求所需要具备的条件或能力
- 对上述的一个条件或能力的一种文档化表达
功能性需求和非功能需求 #
- 功能性需求是软件系统中最常见、最主要和最重要的需求,同时它也是最为复杂的需求,是一个软件产品能够解决用户问题和产生价值的基础
- 非功能需求主要包括性能需求、质量需求、对外接口、约束、数据需求等。
- 其中质量需求是非功能需求中影响最大的需求。
- 可用性、可靠性、可维护性、可移植性、安全性、易用性
需求的三个层次分别描述了什么 #
- 业务需求
- 系统建立的战略出发点,表现为高层次的目标,它描述了组织为什么要开发系统;
- 为了满足用户的业务需求,需求工程师需要描述系统高层次的解决方案,定义系统应具备怎样的特性
- 高层次解决方案与系统特性说明了系统为用户提供的各项功能,限定了系统的范围,帮助用户和开发者确定系统的边界
- 用户需求
- 执行实际工作的用户对系统所能完成的具体任务的期望,描述了系统能够帮助用户做些什么
- 系统级需求
- 用户对系统行为的期望,每个系统级别需求反映了一次外界与系统的交互行为,或者系统的一个实现细节;
- 直接映射为系统行为,定义了系统中需要实现的功能,描述了开发人员需要实现什么
- 一系列系统级需求联系在一起满足一个用户需求,进而满足业务需求
软件配置管理活动 #
- 标识符配置:首先要确定有哪些配置项需要被保存和管理。其次要给配置项确定标识,设置唯一的id。最后要详细说明配置项的特征。
- 版本管理:为每一个刚纳入配置管理的配置项赋予一个初始的版本号,并在发生变更时更新版本号
- 变更管理:已经纳入配置管理中的配置项发生变化时,需要依据变更控制过程进行处理
- 配置审计:配置审计的目标是确定一个项目满足需求的功能和物理特征的程度,确保软件开发工作按照需求规格和设计特征进行,验证配置项的完整性、正确性、一致性和可跟踪性
- 状态报告:配置状态报告是要标识、收集和维持演化中的配置状态信息,也就是在动态演化者的配置项信息及其度量取快照
- 软件发布管理:软件发布管理是将软件配置项发布到开发活动之外,例如发布给客户
单元测试、集成测试、系统测试 #
- 单元测试:测试一个单元接口,是对程序单元进行正确性检验的测试工作
- 集成测试:测试多个单元接口,即对程序模块一次性或采用增量方式组装起来,对系统的接口进行正确性检验的测试工作
- 系统测试:测试全部单元接口,测试关注整个系统的行为
- 单元测试和集成测试更加关注技术上的正确性,重在发现设计缺陷和代码缺陷。系统测试更关注不符合需求的缺陷和需求自身的内在缺陷
持续集成 #
集成是将所有模块组合起来形成整个软件原型系统
持续集成是一种增量性集成,但其提倡尽早集成(不需等到模块开发完才集成,开发之初就利用stub集成)和频繁集成(每次完成一些开发任务,就用完成的程序替换)。
缺陷、错误、失效是什么?有什么关系 #
- 错误:产生不正确的认为行为。人为的原因导致一个不正确的结果。它可以是程序内部的错误,也可以是文档内的错误。甚至是环境方面的问题
- 缺陷:程序或者软件中不正确的步骤、过程或者数据定义等。比如错误的语句或者错误的标量定义。缺陷是错误的具体表现,可以是不正确的文档、程序段以及指令或者数据定义
- 失效:软件系统或单元无法实现需求文档中规定的功能特性或者非功能特性。或者说单元/系统产生的结果与期望交付的服务或者结果存在变差。外部的失效/失败是内部缺陷在执行测试软件的外部反映。它是规范说明的期望值与实际观察到的值、现象等存在偏差。比如不正确的系统反映、系统崩溃、系统死机等
- 关系:人为造成的错误引入到软件工作产品中就编程了缺陷,或者环境因素导致软件中存在瑕疵。加入存在缺陷的代码,进入了运行,这些缺陷就可能会导致系统的不正常,或者导致系统的失效和失败。
4个体系结构视角 #
- 组合视角:关注功能分解和运行时分解、子系统的构造,构建的复用
- 逻辑视角:关注静态结构、类型与实现的复用
- 依赖视角:关注互联、分享
- 信息视角:关注持久化信息
- 接口视角:关注服务的定义、服务的访问
质量模型的可用性 #
- 易学性:新手用户容易学习,能够很快使用系统
- 效率:熟练用户使用系统完成任务的速度
- 易记性:以前使用过软件系统的用户,能够有效记忆或者快速地重新学会使用该系统。
- 出错率:用户使用系统时,会犯多少错,错误有多严重,以及能够从错误中很容易地恢复
- 主观满意度:让用户有良好的体验
软件质量保障三种手段 #
- 评审:由作者之外的其他人来检查产品问题
- 软件测试:主要包括单元、集成、系统测试
- 质量度量:用数字量化的方式描述软件产品
科学与工程的区别 #
- 科学是关于事物的基本原理和事实的有组织、有系统的知识。科学的主要任务是研究世界万物变化的客观规律,他解决“为什么”的问题
- 工程是自然科学或各种专门技术应用到生产部门中而形成的各种学科的总称,其目的在于利用改造自然学科来为人类服务。通过工程可以生产和开发出对社会有用的产品。科学可以作为工程的指导知识,譬如软件工程的指导知识是计算机科学。
软件系统的生命周期 #
- 软件系统的生命周期模型描述软件开发过程中各种活动如何执行的模型。有瀑布模型、原型模型、增量模型、迭代模型、螺旋模型等。
- 以瀑布模型为例,它要求软件开发分为需求分析、软件设计、软件构造、软件测试、软件交付与维护阶段,每个阶段要编写相应的文档,且只有经过审核才能进入下一个阶段。
黑盒与白盒测试的差别 #
- 黑盒测试是基于规格的,将测试对象堪称一个黑盒子,完全基于输入和输出数据来判定测试对象的正确性。
- 白盒测试是基于代码的,将测试对象看作透明,按照测试对象内部的程序结构来设计测试用例进行测试。
- 黑盒测试的方法有:等价类划分、边界值分析、决策表
- 白盒测试的方法有:语句覆盖、条件覆盖、路径覆盖
- 白优:覆盖率高、发现的缺陷数量较多
- 白缺:测试开销大、不能检验需求规格
- 黑优:测试效率高、可以检验规格需求
- 黑缺:覆盖率低、发现缺陷数量较少
策略模式 #
策略模式就是用来封装算法的,但是在实践中,我们发现可以用它来封装几乎任何类型的规则,只要在分析过程中听到需要在不同时间应用不同业务规则,就可以考虑使用策略模式处理这种变化的可能性
-
适用的场景:
-
如果在一个系统里有很多类,他们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为
-
一个系统需要动态地在许多行为中选择一种行为
-
如果一个对象有很多行为,如果不用恰当的模式,这种行为就只好使用多重的条件选择语句来实现
-
-
优点:
-
代码可扩展性,符合面向接口编程ISP
-
提供了可以替换继承关系的方法
-
避免多重条件转移语句
-
-
缺点:
-
客户端必须知道所有策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类
-
策略模式造成很多的策略类,每个具体策略类都会产生一个新类
-
迪米特法则 #
一个软件实体应尽可能少地与其他实体发生相互作用
ATM机取款任务为主题,编写取款的用例 #
取款处理
ID:WithDrawProcess
参与人:用户(取款人),目标是能够尽可能快速地完成取款业务
触发条件:用户将银行卡插入卡槽
前置条件:所插入磁卡是本银行发行且有效状态的银行卡
后置条件:更新账户信息,准确读出取款陷阱至取款槽
正常流程:1.系统对插入卡槽的银行卡进行识别
2.系统显示用户操作界面
3.用户选择取款业务,系统上显示卡上余额
4.用户输入取款金额,系统更新账户信息,并读出相应现金
5.用户选择退卡,系统退回主界面,并动态更新银行基金宣传信息
扩展流程:1a.无效磁卡,吐出银行卡,并提示错误信息
3a.非法字符,系统提示错误并拒绝输入
3b.用户输入金额超过余额,系统提示并拒绝提款
4a.用户提款完成后,系统语音提示用户退卡,防止丢失
特殊需求:1.用户所有需求在3s内得到相应
2.初次使用ATM取款的用户也能快速完成取款业务
代码 #
判断思路 #
- 内聚和耦合。
- 面向对象设计原则。OCP、SRP
2013年-1 #
public class RationalNumber{
private int dividend;
private int divisor;
public RationalNumber(int dividend,int divisor){
if(divisor==0)throw new illegalArgumentException("分母不能为0");
this.dividend=dividend;
this.divisor=divisor;
}
getter setter
public RationalNumber SimpleFraction(RationNumber num){
int x=num.getDividend();
int y=num.getDivisor();
int largestCommonDivisor=getLargestCommonDivisor(x,y);
return new x/largestCommonDivisor,y/largestCommonDivisor
}
public int getLargestCommonDivisor(int x,int y){
x=Math.abs(x);
y=Math.abs(y);
int z=y;
whils(x%y!=0){
z=x%y;
x=y;
y=z;
}
return z;
}
public int getLeastCommonMultiple(int x,int y){
return (x*y)/getLargestCommonDivisor(x,y);
}
//加法
public RationalNumber add(RaionalNumber num){
int dividendOfNum1=this.getDividend();
int divisorOfNum1=this.getDivisor();
int dividendOfNum2=num.getDividend();
int divisorOfNum2=num.getDivisor();
int fenmu=getLeastCommonMultiple(divisorOfNum1,divisorOfNum2);
dividendOfNum1*=(fenmu/divisorOfNum1);
dividendOfNum2*=(fenmu/divisorOfNum2);
int fenzi=dividendOfNum1+dividendOfNum2;
RationalNUmber result = simpleFraction(new RationalNumber(fenzi,fenmu));
return result;
}
}
2013年-2 #
public class Square{
Rectangle rect;
double edge;
public Squre (double edge){
this.rect.setWidth(edge);
this.rect.setLength(edge);
}
public double getArea(){
return rect.getArea();
}
}
// 单一职责原则
public class Square{
public void draw(){
// 依赖GUI对象和GeometricSquare对象绘图
}
}
public GeometricSquare{
public double area(){
//求面积
}
}
2014年-1 #
public interface Factory{
public Employee createEmp(String name);
}
public class EmployeeFactory implements Factory{
public Employee createEmp(String name){
return new SalariedEmployee(name);
}
}
...
public class Department{
private List<Employee> employeeList;
private Factory factory;
...
public Employee addEmployee(String name){
Employee emp=factory.createEmp(name);
emp.setDepartment(this);
employeeList.add(emp);
update();
}
}
2015年1 #
时间内聚考初始化
2017年 #
private Double getTotalSum(List amounts){
Double totalToPay=0.00;
Interator amountSIeterator = amount.iterator();
while(amountsIterator.hasNext){
Amount amount=(Amount) amountSIterator.next();
if(!cancelstatuses.contains(amount.getStatus())){
totalTopay+=amount.doubleValue();
}
}
return new Double(totalToPay);
}
private Double getTotalSumExcludeCancelAmount(List amout){
List newAmount=filter(amounts);
return getTotalSum(newAmounts);
}
private List filter(List amounts){
List res=new ArrayList();
Interator amountSIeterator = amount.iterator();
while(amountsIterator.hasNext()){
Amount amount=(Amount)amountIterator.next();
if(!amount.getIsToCancel()){
res.add(amount);
}
}
return res;
}
2019年-1 #
public class Sales{
SaleList salesList = new SaleList();
...
public double getCommdityPriceById(long CommidityId){
return saleList.getCommdityPrice(CommidityId);
}
}
public class SaleList{
HashMap<Integer, SalesLineItem>salesItemMap = new HashMap<Integer, SalesLineItem>();
public double getCommdityPriceBy(long CommidityId){
SalesLineItem item = salesItemMap.get(id);
return item.getCommodityPrice();
}
}
public class SaleLineList{
Commodity commodity;
...
public double getCommdityPriceBy(long CommidityId){
return commodity.getPrice();
}
}
public class Commodity{
double price;
...
public double getPrice(){
return price;
}
}
2019年-2 #
interface FlyBehavior{
public void fly();
}
class SubSonicFly implements FlyBehavior{
@Override
public void fly();
}
class SuperSonicFly implements FlyBehavior{
@Override
public void fly();
}
interface TakeOffBehavior{
public void takeOff();
}
class VerticalTakeOff implements TakeOffBehavior{
@Override
public void takeOff();
}
class LongDistanceTakeOff implements TakeOffBehavior{
@Override
public void takeOff();
}
abstract class AirCraft{
protected FlyBehavior flyBehavior;
protected TakeOffBehavior takeOffBehavior;
public void fly(){
flyBehavior.fly();
}
public void takeoff(){
flyBehavior.takeoff();
}
}
class AirPlane extends AirCraft{
public AirPlane(){
flyBehavior=new SubSonicFly();
takeOffBehavior=new VerticalTakeoff();
}
}
...
2020年 #
public interface ticket{
public int getPrice();
}
public class StudentTicket implements Ticket{
@Override
public int getPrice(){
return 30;
}
}
...