设计模式学习笔记二UML与面向对象设计原则

3次阅读

共计 5519 个字符,预计需要花费 14 分钟才能阅读完成。

1 UML

1.1 UML

UML(Unified Modeling Language)是对立建模语言,1997 年 11 月 UML1.1 版本提交给 OMG 并正式通过,成为建模语言的个那个也规范。2003 年 6 月 UML2.0 取得正式通过。

1.2 UML 个性

  • U(Unified):对立,UML 交融了多种优良的面向对象建模办法以及多种失去认可的软件工程办法,打消了因办法林立且互相独立而带来的种种不便,集众家之长,股名“对立”。通过对立的示意办法能够让不同常识背景的领域专家,系统分析设计人员以及开发人员能够不便地交换
  • M(Modeling):UML 是一种通用的可视化建模语言,不同与编程语言,UML 通过一些规范的图形符号和文字来对系统进行建模,用于对软件进行形容,可视化解决,结构零碎制品的文档。UML 实用于各种软件开发办法,软件生命周期的各个阶段,各种应用领域以及各种开发工具
  • L(Language):UML 是一种语言,也就意味着它有属于本人的规范表白规定,不是一种相似 Java,C++ 的编程语言,而是一种剖析设计语言,一种建模语言

1.3 UML 构造

UML 构造通常包含以下 4 个局部:视图,图,模型元素以及通用机制。

1.3.1 视图

UML 视图用于从不同的角度来示意待建模的零碎。视图是由许多图形组成的一个形象汇合,在建设一个零碎模型时,只有通过定义多个视图,每个视图显示该零碎的一个特定方面,能力结构出该零碎的残缺蓝图。
UML 视图包含:

  • 用户视图:以用户的观点示意零碎的指标,是所有视图的外围,用于形容零碎的需要
  • 构造视图:零碎的动态行为,形容零碎的动态元素,比方包,类,对象以及它们之间的关系
  • 行为视图:零碎的动静行为,形容零碎的组成元素在零碎运行时的交互关系
  • 实现视图:零碎中逻辑元素的散布,形容零碎中物理文件以及它们之间的关系
  • 环境视图:零碎中物理元素的散布,形容零碎中硬件设施以及他们之间的关系

1.3.2 图

UML 图是形容 UML 视图内容的图形,UML2.0 提供了 13 种图,别离是用例图,类图,对象图,包图,组合结构图,状态图,流动图,程序图,通信图,定时图,交互概览图,组件图和部署图。其中:

  • 用例图对应用户视图
  • 类图,对象图,包图和组合结构图对应构造视图
  • 状态图,流动图,程序图,通信图,定时图和交互概览图对应行为视图
  • 组件图对应实现视图
  • 部署图对应环境视图

1.3.3 模型元素

模型元素是指 UML 图中所应用的一些概念,对应于一般的面向对象概念,如类,对象,音讯以及这些概念之间的关系,如关联关系,泛化关系等。

1.3.4 通用机制

UML 提供的通用机制为模型元素提供额定的正文,信息和语义,这些通用机制也提供了扩大机制,容许用户对 UML 进行扩大,如定义新的建模元素,扩大原有的语义,增加新的非凡信息来扩大模型元素的规定阐明等,以便实用于特定的办法或过程,组织和用户。

2 UML 类图

2.1 类图

类封装了数据和行为,是具备雷同属性,操作,关系的对象汇合的总称。类图是用呈现在零碎中不同类来形容零碎的动态构造,次要形容不同的类以及它们之间的关系。
在 UML 中,类图蕴含类名,属性以及操作。如上面的 Employee 类:

类个别由三局部组成:

  • 类名
  • 属性
  • 操作

2.1.1 类名

类名就是类的名字,一个字符串。

2.1.2 属性

类的成员变量,个别的格局为

可见性 名称 : 类型 [= 默认值]

可见性示意该属性对于类外的元素是否可见,包含:

  • 私有:+
  • 公有:-
  • 受爱护:#
  • 包:~

2.1.3 操作

UML 规定操作的定义形式为:

可见性 名称(参数列表)[: 返回类型]
  • 可见性与属性可见性的定义统一
  • 参数列表示意办法的参数,语法与属性定义相似,用 , 分隔

2.2 类之间的关系

UML 提供了四种不同的形式示意类与类之间的关系:

  • 关联关系
  • 依赖关系
  • 泛化关系
  • 接口与实现关系

上面一一看一下。

3 关联关系

关联关系是一种结构化关系,用于示意一类对象与另一类对象之间有分割。在 UML 中用实线连贯有关联关系的类。能够在关联线上标注角色名,关系的两端代表两种不同的角色,因而在一个关联关系中能够蕴含两个角色名,角色名不是必须的,但能够使类之间的关系更加明确。
例如在一个登录界面类 LoginForm 蕴含一个JButton


UML 中关联通常包含以下六种模式:

  • 双向关联
  • 单向关联
  • 自关联
  • 多重性关联
  • 聚合关系
  • 组合关系

3.1 双向关联

默认状况下关联是双向的,例如顾客购买商品并领有商品,反之卖出的商品总是某个顾客与之相关联:

3.2 单向关联

关联也能够是单向的,在 UML 中关联用带箭头的实线示意,比方顾客领有地址:

3.3 自关联

零碎中可能会存在一些类的属性对象类型为该类自身,这种非凡的关联关系为自关联,常见于链表:

3.4 多重性关联

多重性关联又称为多重性关联分割,示意两个关联对象在数量上的对应关系。在 UML 中,对象之间的多重性能够间接在关联直线上用一个数字或者一个数字范畴来示意。常见的示意形式如下:

例如一个界面能够具备 0 个或多个按钮,然而一个按钮只能从属于一个界面:

3.5 聚合关系

聚合关系示意整体与局部的关系,应用空心菱形示意。聚合关系中局部是整体的一部分,然而局部能够脱离整体独立存在,比方引擎是汽车的一部分,然而引擎能够独立于汽车存在:

3.6 组合关系

组合关系也示意整体与局部之间的关系,然而局部不能脱离整体存在。组合关系应用实心菱形示意。比方人的头和嘴巴是组合关系:

4 依赖关系

依赖关系是一种应用关系,在须要示意“一个事物应用另一个事物”时应用依赖关系。UML 中依赖关系用带箭头的虚线示意,由依赖的一方指向被依赖的一方。例如驾驶员开车,开车须要车,也就是驾驶员依赖于车:

5 泛化关系

泛化关系也就是继承关系,用于形容父类与之类之间的关系,父类又叫基类或者超类,子类又称作派生类。UML 中泛化关系用带空心三角形的直线示意,箭头指向基类:

6 接口与实现关系

很多语言比方 Java,C# 都有接口的概念,接口通常没有属性,所有是操作都是形象的,只有操作的申明没有操作的实现。UML 中应用 <<Interface>> 示意接口:

类与接口之间的实现关系应用空心三角形 + 虚线示意:

7 面向对象设计准则

7.1 概述

面向对象设计的指标之一是反对可维护性复用,一方面须要实现设计方案或者源代码的重用,一方面要确保零碎可能易于扩大和批改,具备较好的灵活性。面向对象设计准则由此诞生,它们蕴含于很多设计模式中,是从许多计划总结进去的指导性准则。常见的 7 种面向对象设计准则如下:

  • 繁多权责准则
  • 开闭准则
  • 里氏代换准则
  • 依赖倒转准则
  • 接口隔离准则
  • 合成复用准则
  • 迪米特法令

7.2 繁多职责准则 SRP

** 繁多权责准则(Single Responsibility Principal):一个类只负责一个性能畛域中的相应职责。
或者能够定义为:就一个类而言,应该只有一个引起它变动的起因。**

繁多权责准则的核心思想是:一个类不能太“累”。一个类(大到模块,小到办法)承当的职责越多,被复用的可能性越小,而且一个类承当的职责过多,就相当于将这些职责耦合在一起,当其中一个职责变动时,可能会影响其余职责的运作,因而须要将职责拆散,封装在不同的类中,行将不同的变动起因封装在不同的类中。繁多权责准则是实现高内聚,低耦合的指导方针。

7.3 开闭准则 OCP

开闭准则(Open-Closed Principle):一个软件实体该当对扩大凋谢,对批改敞开。即软件实体应尽量不批改原有代码的状况下进行扩大。

其中软件实体能够是一个软件模块,一个由多个类组成的部分构造或者一个独立的类。
一个软件设计合乎开闭准则,则能够十分不便地对其进行扩大,而且在扩大时毋庸批改现有代码,使得软件系统在领有适应性和灵活性的同时具备较好的稳定性和延续性。

为了满足开闭准则,须要对系统进行抽象化设计,抽象化是开闭准则的要害。能够通过接口,抽象类等定义形象层,通过具体类进行扩大,批改零碎的行为时无需批改形象层,只须要减少新的具体类来实现新的业务性能即可,实现在不批改已有代码的根底上扩大零碎的性能,达到开闭准则的要求。

7.4 里氏代换准则 LSP

里氏代换准则(Liskov Substitution Principle):所有援用基类 / 父类的中央必须能通明地应用其子类的对象。

简略地说就是父类呈现的中央能够用子类代替,程序不会产生任何的谬误和异样。应用里氏代换准则时,应该将父类设计为抽象类或者接口,让子类继承父类或实现父类接口,并实现父类中申明的办法,运行时,子类实例代替父类实例,能够很不便地扩大零碎的性能,毋庸批改原有子类的代码,减少新的性能能够通过减少一个新的子类来实现。

7.5 依赖倒转准则 DIP

依赖倒转准则(Dependency Inversion Principal):形象不应该依赖具体细节,细节该当依赖于形象,换言之要针对接口编程,而不是针对实现编程。

依赖倒转准则要求程序在源代码中传递参数时或者在关联关系中,尽量援用高层次的形象层类,即便有接口和抽象类进行变量类型申明,参数类型申明,办法返回类型申明以及数据类型的转换等,而不是用具体类来做。一个具体类应该只实现接口或者抽象类中申明过的办法,而不要给出多余的办法,否则将无奈调用在子类中新增的办法。

在实现依赖倒转准则时,须要针对形象层进行编程,而将具体类的对象通过依赖注入(Dependency Injection)的形式注入到其余对象中。依赖注入是指当一个对象要与其余对象产生依赖关系时,通过形象来注入所依赖的对象。罕用的注入形式包含:

  • 结构注入:通过构造函数来传入具体类的对象
  • 设值注入(setter 注入):通过 setter 来传入具体类对象
  • 接口注入:通过实现在接口中申明的办法来传入具体类对象

下面的办法在定义时应用形象类型,在运行时传入具体类型的对象,由子类对象来笼罩父类对象。

7.6 接口隔离准则 ISP

接口隔离准则(Interface Segregation Principal):应用多个专门的接口,而不应用繁多的总接口,即客户端不应该依赖于那些它不须要的接口。

也就是说,当一个接口太大时须要划分为更小的接口,应用该接口的客户端仅需晓得与之相干的办法。每一个接口应该承当一种绝对独立的角色,这里的接口有两层意思:

  • 一种是指一个类型所具备的办法特色的汇合,仅仅是一种逻辑上的形象
  • 另一种是指某个语言具体接口的定义,有严格的定义和构造,比方 Java 中的 interface

ISP 对两种不同含意的表达方式有所不同:

  • 当接口了解成一个类型所提供的所有办法特色的汇合时,这就是一种逻辑上的概念,接口的划分将间接带来类型的划分,能够把接口了解成角色,一个接口只能代表一个角色,每个角色都有它特定的一个接口,此时这个准则能够叫“角色隔离准则”
  • 把接口了解成广义的特定语言的接口,ISP 表白的意思是接口仅仅提供客户端须要的行为,客户端不须要的行为则暗藏起来,该当为客户端提供尽可能小的接口,而不提供大的总接口。接口应尽量细化,同时接口中的办法应该尽量少,每个接口中只蕴含一个客户端(如子模块或者业务逻辑类)所需的办法即可,这种机制也叫“定制服务”

应用接口隔离准则时,留神管制接口的粒度:

  • 接口太小导致接口泛滥,不利于保护
  • 接口太大将违反 ISP,灵活性差,应用不不便

一般而言接口中仅蕴含为某一类用户定制的办法即可。

7.7 合成复用准则 CRP

合成复用准则(Composite Reuse Principal):尽量应用对象组合而不是继承来达成复用目标。

合成复用准则又叫组合 / 聚合复用准则(Composition/Aggregate Reuse Principal),就是在一个新对象中通过关联关系(组合 / 聚合)对对象进行重用而不是应用继承。

面向对象设计中,能够通过两种办法在不同环境中复用已有的设计和实现:

  • 继承
  • 组合 / 聚合

7.7.1 继承

继承须要严格遵循里氏代换准则,无效应用继承会有助于对问题的了解,升高复杂度,而滥用继承反而会减少零碎构建和保护的难度以及零碎的复杂度。继承次要带来的问题是会破环零碎的封装性,因为继承会将基类实现细节裸露给子类,因为基类外部细节对子类可见,因而叫“白箱复用”。一般而言两个类之间的关系是“Is-A”关系就能够应用继承。

7.7.2 组合 / 聚合

只管能够通过继承来对代码进行复用,一般来说优先思考组合 / 聚合。组合 / 聚合能够使零碎更加灵便,升高类与类之间的耦合度。因为新对象能够间接调用已有对象的性能,这样做能够使成员对象的外部实现细节对新对象不可见,所以这种复用叫“黑箱复用”。一般而言两个类之间的关系是“Has-A”关系就能够应用组合 / 聚合。

7.8 迪米特法令 LoD

迪米特法令(Law of Demeter):一个软件实体该当尽可能少地与其余实体产生相互作用。

迪米特法令又叫起码常识准则(Least Knowledge Principal,LKP),迪米特法令会对软件实体之间通信的宽度与深度进行限度,能够升高零碎的耦合度,使类与类之间放弃松耦合。
迪米特法令还有几种定义模式:不要和“陌生人”谈话,只与间接敌人通信。对于一个对象“敌人”能够是以下几类:

  • 对象自身(this)
  • 以参数模式传入的对象
  • 成员对象
  • 如果成员对象是一个汇合,那么汇合中的元素也是“敌人”
  • 以后对象所创立的对象

满足上述条件之一即是“敌人”,否则就是“陌生人”,不能和“陌生人”产生间接交互。
迪米特法令要求设计零碎时尽量减少对象之间的交互,通过引入一个正当的两头类来升高现有对象之间的耦合度。利用迪米特法令时须要留神几点:

  • 优先将类设计为不变类
  • 类划分上尽量创立松耦合的类
  • 类结构设计上尽量升高成员变量和成员函数的拜访权限
  • 在对其余类的援用上,一个对象对其余对象的援用该当降到最低

8 总结

如果感觉文章难看,欢送点赞。

同时欢送关注微信公众号:氷泠之路。

正文完
 0