软件工程
一、软件开发方法
1、软件开发方法
结构化法
- 用户至上
- 严格区分工作阶段,每阶段有任务与成果
- 强调系统开发过程的整体性和全局性
- 系统开发过程工程化,文档资料标准化
- 自顶向下,逐步分解(求精)
原型法
- 适用于需求不明确的开发
- 包括抛弃型原型和进化型原型
面向对象方法
- 更好的复用性
- 关键在于建立一个全面、合理、统一的模型
- 分析、设计、实现三个阶段,界限不明确
面向服务的方法
- SO方法有三个主要的抽象级别:操作、服务、业务流程
- SOAD分为三个层次:基础设计层(底层服务构件)、应用结构层(服务之间的接口和服务级协定)和业务组织层(业务流程建模和服务流程编排)
- 服务建模:分为服务发现、服务规约和服务实现三个阶段
2、软件开发模型
瀑布模型
适用于需求明确的项目
演化模型
增量模型
螺旋模型
适合大型的系统
原型模型
喷泉模型
V模型
迭代模型/迭代开发方法
快速应用开发
构件组装模型/基于构件的开发方法
统一过程/统一开发方法
敏捷开发方法
模型驱动的开发方法
基于架构的开发方法
二、需求工程
1、需求分析
2、UML
3、4+1视图
4、用例图
4、包含、扩展、泛化
5、类图和对象图
类图(class diagram):类图描述一组类、接口、协作和它们之间的关系
对象图(object diagram): 对象图描述一组对象和它们之间的关系。对象图描述了在类图中所建立的事务实例的静态快照。
6、活动图![](https://i-blog.csdnimg.cn/blog_migrate/e829793319dc36da30745389c88859ff.png)
三、软件系统建模
四、系统设计
设计模式
设计模式的概念
架构模式:软件设计中的高层决策,例如C/S结构就属于架构模式,架构模式反映了开发软件系统过程中所作的基本设计决策
设计模式:主要关注软件系统的设计,与具体的实现语言无关
惯用法:最低层的模式,关注软件系统的设计与实现,实现时通过某种特定的程序设计语言来描述构件与构件之间的关系。每种编程语言都有它自己特定的模式,即语言的惯用法。例如引用计数就是C++语言中的一种惯用法
设计模式的六大原则
- 1、开闭原则(Open Close Principle):对扩展开放,对修改关闭。使程序的扩展性好,易于维护和升级。
- 2、里氏替换原则(Liskov Substitution Principle):任何基类出现的地方,子类一定可以出现。
- 3、依赖倒转原则(Dependence Inversion Principle):针对接口编程,依赖于抽象而不依赖于具体。
- 4、接口隔离原则(Interface Segregation Principle):使用多个接口比使用单个接口要好。
- 5、迪米特原则 最少知道原则(Demeter Principle):一个实体类应当尽量少的与其他实体之间发生相互作用,使系统功能模块相对独立。
- 6、合成复用原则(Composite Reuse Principle):尽量使用合成、聚合的方式,而不是使用继承。
设计模式的分类
创建型模式:创建对象
1、工厂方法(Factory Method):动态生产对象。定义一个创建对象的接口,但由子类决定需要实例化哪个类。工厂方法使得子类实例化的过程推迟。
2、抽象工厂(Abstract Factory):生产成系列对象。 提供一个接口,可以创建一系列相关或相互依赖的对象,而无需指定它们具体的类。
3、原型(Prototype):克隆对象。用原型实例指定创建对象的类型,并且通过拷贝这个原型来创建新的对象。
- JAVA 中的 Object clone() 方法,实现 Cloneable 接口,重写 clone()
- 浅拷贝是通过实现Cloneable接口,深拷贝是通过实现Serializable读取二进制流
- 浅克隆只能克隆对象的基本数据类型(int、double、byte、boolean、char)
- 无论原型对象成员变量是基本数据类型还是引用类型,深拷贝都可以实现克隆
4、构建器(Builder):复杂对象构造。将一个复杂类的表示与其构造相分离,使得相同的构建过程能够得出不同的表示。
5、单例模式(Singleton):单实例。保证一个类只有一个实例,并提供一个访问它的全局访问点。
- Spring IOC容器中的bean默认就是单例
- JDK中Runtime类,采用饿汉方式,用于检测JVM运行状态
- Redis连接对象就是单例的
- SpringBoot中的controller、service、dao层中通过@autowire的依赖注入对象默认都是单例的
结构型模式:更大的结构
6、适配器(Adapter):转换接口。将一个类的接口转换成用户希望得到的另一种接口。它使原本不相容的接口得以协同工作。
- JDBC就是使用最多的设计模式。JDBC给出一个客户端通用的抽象接口,每一个具体数据库厂商,如SQL Server、Oracle、MySQL等,就会开发JDBC驱动,就是一个介于JDBC接口和数据引擎接口之间的适配器软件
7、桥接(Bridge):继承树拆分。将类的抽象部分和它的实现部分分离开来,使它们可以独立的变化。
- 主要解决在有多种可能会变化的情况下,用继承会造成类爆炸问题,扩展起来不灵活。
8、组合(Composite):树形目录结构。将对象组合成树型结构以表示”整体-部分“的层次结构,使得用户对单个对象和组合对象的使用具有一致性。
9、装饰(Decorator):动态附加职责。动态地给一个对象添加一些额外地职责。它提供了用子类扩展功能地一个灵活地替代,比派生一个子类更加灵活。
- 在JDK中应用场景,IO流:
- 抽象组件(Component):InputStream
- 被装饰者(ConcreteComponent):FileInputStream、ByteArrayInputStream
- 装饰者组件(Decorator):FilterInputStream
- 具体装饰物(ConcreteDecorator):BufferedInputStream、DataInputStream
10、外观(Facade):对外统一接口。定义一个高层接口,为子系统中地一组接口提供一个一致地外观,从而简化了该子系统地使用。
11、享元(Flyweight):汉字编码。提供支持大量细粒度对象共享地有效方法。
- 数据库连接池
- JDK中String类
- 在有大量对象时,有可能会造成内存溢出,我们把其中共同的部分抽象出来,如果有相同的业务请求,直接返回在内存中已有的对象,避免重新创建。
12、代理(Proxy):快捷方式。为其他对象提供一种代理以控制这个对象地访问。
- 静态代理:在程序运行前,代理类的.class文件就已经存在
- 动态代理:程序运行时,运用反射机制动态创建而成
- JDK动态代理:要求目标对象实现一个接口
- CGLib动态代理:在内存中构建一个子类对象从而实现对目标对象功能的扩展
- JDK动态代理时自带的,CGLib需要引入第三方包
- CGLib动态代理基于继承来实现,无法对final类,private方法,static方法实现代理
Spring AOP中的代理使用的默认策略:
- 目标对象实现了接口,默认用JDK动态代理
- 目标对象没有实现接口,采用CGLib动态代理
- 目标对象实现了接口,依然可以指定使用CGLib动态代理
行为型模式:(交互及职责分配)
13、职责链(Chain of Responsibility):传递职责。通过给多个对象处理请求地机会,减少请求地发送者与接收者之间地耦合。将接受对象链接起来,在链中传递请求,直到有一个对象处理这个请求。
- SpringBoot里面的拦截器、过滤器
14、命令(Command):日志记录,可撤销。将一个请求封装为一个对象,从而可用不同地请求对客户进行参数化,将请求排队或记录请求日志,支持可撤销地操作。
15、解释器(Interpreter):虚拟机地机制。给定一种语言,定义它的文法表示,并定义一个解释器,该解释器用来根据文法表示来解释语言中的句子。
16、迭代器(Iterator):数据集。提供一种方法来顺序访问一个聚合对象中的各个元素,而不需要暴露该对象的内部表示。
- JDK中Iterator类
17、中介者(Mediator):不直接引用。用一个中介对象来封装一系列的对象交互。它使各个对象不需要显式地相互调用,从而达到低耦合,还可以独立地改变对象间地交互。
18、备忘录、快照(Memento):游戏存档。在不破坏封装地前提下,捕获一个对象地内部状态,并在该对象之外保存这个状态,从而可以在以后将该对象恢复到原先保存地状态。
19、观察者(Observer):联动。定义对象间地一种一对多地依赖关系,当一个对象地状态发生改变时,所有依赖于它地对象都得到通知并自动更新。
20、状态(State):状态变成类。允许一个对象在其内部状态改变时改变它地行为。
- 对象的行为依赖于它的状态,并且可以根据状态去改变相关行为。
21、策略(Strategy):多方案切换。定义一系列算法,把他们一个个封装起来,并且使它们之间可以相互替换,从而让算法可以独立于使用它地用户而变化。
- JDK中Comparator接口常用的compare()方法
22、模板方法(Template Method):框架。定义一个操作中的算法骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重新定义算法的某些特定步骤。
- 设计一个系统时知道了算法所需的关键步骤,且确定了这些步骤的执行顺序,单某些步骤的具体实现还未知,可以延迟到子类进行完成。
- Spring中JDBCTemplate
23、访问者(Visitor):数据与操作分离。表示一个作用于某对象结构中的各个元素的操作,使得在不改变各个元素的类的前提下定义作用于这些元素的新操作。
加粗的表示可以是类模式,也可以是对象模式;其他表示只是对象模式
红色字体表示速记关键字
五、测试与评审
软件测试
- 动态测试:黑盒测试、白盒测试、灰盒测试
- 静态测试:桌前检查、代码审查、代码走查
- 黑盒测试:等价类划分、边界值分析、错误推测、因果图
- 白盒测试:基本路径测试、循环覆盖测试、逻辑覆盖测试
测试阶段:
- 单元测试:模块测试、模块功能、性能、接口
- 集成测试:模块间的接口
- 确认测试:验证软件与需求的一致性。内部确认测试,Alpha测试、Beta测试,验收测试
- 系统测试:真实环境下,验证完整的软件配置项能否和系统正确连接
- 回归测试:测试软件变更后,变更部分的正确性对变更需求的符合性。
面向对象的测试:
- 算法层(单元测试):包括等价类划分测试、组合功能测试(基于判定表的测试)、递归函数测试和多态消息测试
- 类层(模块测试):包括不变式边界测试、模态类测试和非模态类测试
- 模板层、类树层(集成测试):包括多态服务测试和展平测试
- 系统层(系统测试)
软件调试:
软件调试方法:
- 蛮力法:主要思想是“通过计算机找错”,低效,耗时
- 回溯法:从出错处人工沿控制流程往回追踪,直至发现出错的根源。复杂程序由于回溯路径多,难以实施。
- 原因排除法:主要思想是演绎和归纳,用二分法实现
软件调试与测试的区别:
- 测试的目的是找出存在的错误,而调试的目的是定位错误并修改程序以修正错误
- 调试是测试之后的活动,测试和调试在目标、方法和思路上都有所不同。
- 测试从一个已知的条件开始,使用预先定义的过程,有预知的结果,调试从一个未知的条件开始,结束的过程不可预计
- 测试过程可以事先设计,进度可以事先确定,调试不能描述过程或持续时间
六、系统运行与软件维护
系统转换计划
淘汰策略:遗留系统的技术含量较低,且具有较低的业务价值。对遗留系统的完全淘汰是企业资源的根本浪费,系统分析师应该善于”变废为宝“,通过对遗留系统功能的理解和借鉴,可以帮助新系统的设计,降低新系统开发的风险。
继承策略:遗留系统的技术含量较低,已经满足企业运作的功能或性能要求,但具有较高的商业价值,目前企业的业务尚紧密依赖该系统。对这种遗留系统的演化策略为继承。在开发新系统时,需要完全兼容遗留系统的功能模型和数据模型。为了保证业务的连续性,新老系统必须并行运行一段时间,再逐渐切换到新系统上运行。
改造策略:遗留系统具有较高的业务价值,基本上能够满足企业业务运作和决策支持的需要。这种系统可能建成的时间还很短,对这种遗留系统的演化策略为改造。改造包括系统功能的增强和数据模型的改造两个方面。系统功能的增强是指在原有系统的基础上增加新的应用要求。对遗留系统本身不做改变,数据模型的改造是指将遗留系统的旧数据模型向新的数据模型的转化。
集成策略:遗留系统的技术含量较高,但是其业务价值较低,可能只是完成某个部门或者子公司的业务管理。这种系统再各自的局部领域里工作良好,但对于整个企业来说,存在多个这样的系统,不同的系统基于不同的平台、不同的数据模型,形成了一个个信息孤岛,对这种遗留系统的演化策略为集成。
系统运行与维护
正确性维护:改正正在系统开发阶段已发生而系统测试阶段尚未发现的错误。
适应性维护:使应用软件适应信息技术变化和管理需求变化而进行的修改。企业外部市场环境和管理需求的不断变化也使得各级管理人员不断提出新的信息需求。
完善性维护:扩充功能和改善性能而进行的修改。对已有的软件系统增加一些在系统分析和设计阶段中没有规定的功能与性能特征。
预防性维护:改进应用软件的可靠性和维护性,为了适应未来的软硬件环境的变化,应主动增加预防性的新的功能,以使用系统适应各类变化而不被淘汰。如将专用报表功能改成通用报表生成功能,以适应将来报表格式的变化。