软件建模基础

摘录自某PPT

文章目录

软件建模基础

设计模式 | 菜鸟教程
软件设计模式概述 | C语言中文网

0 软件质量属性

0.1 如何评价代码质量

    1. 可维护性(maintainability)
      对于一个项目来说,维护代码的时间远远大于编写代码的时间。“代码不易维护”就是指,修改或者添加代码需要冒着极大的引入新 bug 的风险,并且需要花费很长的时间才能完成。
    1. 可读性(readability)
      “Any fool can write code that a computer can understand. Good programmers write code that humans can understand.”
      代码的可读性在非常大程度上会影响代码的可维护性。
    1. 可扩展性(extensibility)
      代码预留功能扩展点,可以把新功能代码,直接插到扩展点上,而不需要因为要添加一个功能而大动干戈。
    1. 灵活性(flexibility)
      灵活性是一个抽象的评价标准。
      如果一段代码易扩展、易复用或者易用,我们都可以称这段代码写得比较灵活。
    1. 简洁性(simplicity)
      “Keep It Simple,Stupid”
      代码简单、逻辑清晰,也就意味着易读、易维护。
      思从深而行从简,真正的高手能云淡风轻地用最简单的方法解决最复杂的问题。
    1. 可复用性(reusability)
      DRY(Don’t Repeat Yourself)
      可复用性是很多设计原则、思想、模式等所要达到的最终效果。
    1. 可测试性(testability)

0.2 软件质量属性

(Bass,Clements,and Kazman 2003)

  • 可维护性(maintainability)在软件部署之后它能够被更改的程度。
  • 可修改性(modifiability)在最初开发期间和最初开发之后软件能够被修改的程度。
  • 可测试性(testability)软件能够被测试的程度。
  • 可追踪性(traceability)每一个阶段的产品能够被追踪到上一个阶段产品的程度。
  • 可伸缩性(scalability)在最初部署之后系统能够成长的程度。
  • 可复用性(reusability)软件能够被复用的程度。
  • 性能(performance)系统满足其性能目标的程度,例如吞吐量和响应时间。
  • 安全性(security)系统抵御安全威胁的程度。
  • 可用性(availability)系统能够解决系统失效问题的程度。

1 面向对象

1.0 面向对象知识点

  • 面向对象的四大特性:封装、抽象、继承、多态
  • 面向对象编程与面向过程编程的区别和联系
  • 面向对象分析、面向对象设计、面向对象编程
  • 接口和抽象类的区别以及各自的应用场景
  • 基于接口而非实现编程的设计思想
  • 多用组合少用继承的设计思想
  • 面向过程的贫血模型和面向对象的充血模型

1.1 面向对象四大特性

1.1 (封装)

封装(Encapsulation)封装也叫作信息隐藏或者数据访问保护。类通过暴露有限的访问接口,授权外部仅能通过类提供的方式(或者叫函数)来访问内部信息或者数据。

封装的意义:如果我们对类中属性的访问不做限制,那任何代码都可以访问、修改类中的属性,虽然这样看起来更加灵活,但从另一方面来说,过度灵活也意味着不可控,属性可以随意被以各种奇葩的方式修改,而且修改逻辑可能散落在代码中的各个角落,势必影响代码的可读性、可维护性。除此之外,类仅仅通过有限的方法暴露必要的操作,也能提高类的易用性。如果我们把类属性都暴露给类的调用者,调用者想要正确地操作这些属性,就势必要对业务细节有足够的了解。而这对于调用者来说也是一种负担。

1.1 (抽象)

抽象(Abstraction)隐藏方法的具体实现,让调用者只需要关心方法提供了哪些功能,并不需要知道这些功能是如何实现的。我们常借助编程语言提供的接口类(interface)或者抽象类(abstract)这两种语法机制,来实现抽象这一特性。

抽象的意义:抽象及其前面讲到的封装都是人类处理复杂性的有效手段。在面对复杂系统的时候,人脑能承受的信息复杂程度是有限的,所以我们必须忽略掉一些非关键性的实现细节。很多设计原则都体现了抽象这种设计思想,比如基于接口而非实现编程、开闭原则、代码解耦等。我们在定义(或者叫命名)类的方法的时候,也要有抽象思维,不要在方法定义中,暴露太多的实现细节,以保证在某个时间点需要改变方法的实现逻辑的时候,不用去修改其定义。

1.1 (继承)

继承(Inheritance)继承是用来表示类之间的 is-a 关系,从继承关系上来讲,继承可以分为两种模式,单继承和多继承。单继承表示一个子类只继承一个父类,多继承表示一个子类可以继承多个父类,比如猫既是哺乳动物,又是爬行动物。但在Java和.Net等只能单继承,更提倡面向接口编程。

继承的意义:继承最大的一个好处就是代码复用。假如两个类有一些相同的属性和方法,我们就可以将这些相同的部分,抽取到父类中,让两个子类继承父类。通过继承来关联两个类,反应真实世界中的这种关系,非常符合人类的认知,而且,从设计的角度来说,也有一种结构美感。不过,过度使用继承,继承层次过深过复杂,就会导致代码可读性、可维护性变差。

1.1 (多态)

多态(Polymorphism)顾名思义,一个接口,多种形态。子类可以替换父类,在实际的代码运行过程中,调用子类的方法实现。同样是一个绘图(draw)的方法,如果以正方形调用,则绘制出一个正方形;如果以圆形调用,则画出的是圆形。

多态的意义:只使用封装和继承的编程方式,称之为基于对象(Object Based)编程,而只有把多态加进来,才能称之为面向对象(Object Oriented)编程。多态特性能提高代码的可扩展性和复用性。除此之外,多态也是很多设计模式、设计原则、编程技巧的代码实现基础,比如策略模式、基于接口而非实现编程、依赖倒置原则、里式替换原则、利用多态去掉冗长的 if-else 语句等等。

1.2 面向对象 VS 面向过程

面向对象和面向过程两种编程风格并不是非黑即白、完全对立的。在用面向对象编程语言开发的软件中,面向过程风格的代码并不少见,甚至在一些标准的开发库(比如 JDK、Apache Commons、Google Guava)中,也有很多面向过程风格的代码。
不管使用面向过程还是面向对象哪种风格来写代码,我们最终的目的还是写出易维护、易读、易复用、易扩展的高质量代码。只要我们能避免面向过程编程风格的一些弊端,控制好它的副作用,在掌控范围内为我们所用,我们就大可不用避讳在面向对象编程中写面向过程风格的代码。

1.3 OOA、OOD、OOP

面向对象分析就是要搞清楚做什么,面向对象设计就是要搞清楚怎么做,面向对象编程就是将分析和设计的的结果翻译成代码的过程。

需求分析的过程实际上是一个不断迭代优化的过程。我们不要试图一下就给出一个完美的解决方案,而是先给出一个粗糙的、基础的方案,有一个迭代的基础,然后再慢慢优化。

面向对象设计和实现要做的事情就是把合适的代码放到合适的类中。至于到底选择哪种划分方法,判定的标准是让代码尽量地满足“松耦合、高内聚”、单一职责、对扩展开放对修改关闭等我们之前讲到的各种设计原则和思想,尽量地做到代码可复用、易读、易扩展、易维护。

面向对象分析的产出是详细的需求描述。

面向对象设计的产出是类。

1.3 面向对象设计

划分职责进而识别出有哪些类 根据需求描述,我们把其中涉及的功能点,一个一个罗列出来,然后再去看哪些功能点职责相近,操作同样的属性,可否归为同一个类。
定义类及其属性和方法 我们识别出需求描述中的动词,作为候选的方法,再进一步过滤筛选出真正的方法,把功能点中涉及的名词,作为候选属性,然后同样再进行过滤筛选。
定义类与类之间的交互关系 UML 统一建模语言中定义了六种类之间的关系。它们分别是:泛化、实现、关联、聚合、组合、依赖。我们从更加贴近编程的角度,对类与类之间的关系做了调整,保留了四个关系:泛化、实现、组合、依赖。
将类组装起来并提供执行入口 我们要将所有的类组装在一起,提供一个执行入口。这个入口可能是一个 main() 函数,也可能是一组给外部用的 API 接口。通过这个入口,我们能触发整个代码跑起来。

1.4 接口 VS 抽象类

抽象类是对成员变量和方法的抽象,是一种 is-a 关系,是为了解决代码复用问题。

接口仅仅是对方法的抽象,是一种 has-a 关系,表示具有某一组行为特性,是为了解决解耦问题,隔离接口和具体的实现,提高代码的扩展性。

什么时候该用抽象类?什么时候该用接口?实际上,判断的标准很简单。如果要表示一种 is-a 的关系,并且是为了解决代码复用问题,我们就用抽象类;如果要表示一种 has-a 关系,并且是为了解决抽象而非代码复用问题,那我们就用接口。

在一个面向对象的系统中,系统的各种功能是由许许多多的不同对象协作完成的。在这种情况下,各个对象内部是如何实现自己的,对系统设计人员来讲就不那么重要了;而各个对象之间的协作关系则成为系统设计的关键。小到不同类之间的通信,大到各模块之间的交互,在系统设计之初都是要着重考虑的,这也是系统设计的主要工作内容。面向接口编程就是指按照这种思想来编程。

1.5 基于接口而非实现编程

应用这条原则,可以将接口和实现相分离,封装不稳定的实现,暴露稳定的接口。上游系统面向接口而非实现编程,不依赖不稳定的实现细节,这样当实现发生变化的时候,上游系统的代码基本上不需要做改动,以此来降低耦合性,提高扩展性。

实际上,“基于接口而非实现编程”这条原则的另一个表述方式是&#

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值