本项目是一个Java设计模式的实战教程,包含了23中GoF设计模式的Java实现以及UML基础知识和软件设计的七大原则说明内容.适合初识设计模式的程序员学习.通过本项目,你可以了解到如何进行架构设计,代码解耦合,系统重构等思想.
统一建模语言(Unified Modeling Language, UML)是一种面向对象系统的产品进行说明,可视化和编制文档的标准语言,是非专利的第三代建模和规约语言.UML是一种面向对象设计的建模工具,是在开发阶段说明,可视化,构建和书写一个面向对象软件密集系统的制品的开放方法,但独立于任何具体的程序设计语言.
UML最佳应用是工程实践,在对大规模,复杂系统进行建模方面,特别是软件架构层次,已经被验证有效,UML模型大多以图表的方式表现出来.一份典型的建模图表通常包含几个块或框,连接线和作为模型附加信息的文本.这些虽简单却非常重要,在UML规则中相互联系和扩展.
UML建模的核心是模型,模型是实现的简化,真实系统的抽象.UML提供了系统的设计蓝图.当给软件系统建模时,需要采用通用的符号语言,这种描述模型所使用的语言被称为建模语言.在UML中,所有的描述由事务,关系和图这些构件组成.
事物是抽象化的最终结果,分为结构事物,行为事物,分组事物和注释事物.
结构事物是模型中的静态部分,用以呈现概念或实体的表现元素
事物 | 解释 | 图例 |
---|---|---|
类(Class) | 具有相同属性,方法,关系和语义的对象集合 | |
接口(Interface) | 指一个类或构件的一个服务的操作集合,它仅仅定义了一组操作规范,并没有给出这组操作的具体实现 | |
用例(User Case) | 指对一组动作序列的描述,系统执行这些动作将产生一个对特定的参与者(Actor)有价值且可观察的结果 | |
协作(Collaborations) | 定义元素之间的相互作用 | |
组件(Component) | 描述物理系统的一部分 | |
活动类(Active Class) | 指对象有一个或多个进程或线程.活动类和类很相像,只是它的对象代表的元素行为和其他元素是同时存在的 | |
节点(Node) | 定义为运行时存在的物理元素 |
行为事物是指UML建模中的动态部分.
事物 | 解释 | 图例 |
---|---|---|
交互(Interaction) | 包括一组元素之间的消息交换 | |
状态机(State Machine) | 由一系列对象的状态组成 |
目前只有一种分组事物,即包.包纯粹是概念上的,只存在于开发阶段,结构事物,行为事物甚至分组事物都有可能放在一个包中.
事物 | 解释 | 图例 |
---|---|---|
包(Package) | UML中唯一的组织机制 |
注释事物是解释UML模型元素的部分.
事物 | 解释 | 图例 |
---|---|---|
注释 | 用于解析说明UML元素 |
UML将事物之间的联系归纳为6种,并用对应的图形类表示.
事物关系 | 说明 | 图例 |
---|---|---|
关联(Association) | 表示一种拥有的关系,具有方向性.如果一 个类单方向地访问另一个类,则称为单向 关联;如果两个类的想可以互相访问,则称为 双向关联,一个对象能访问关联对象的数目叫作"多重性". |
|
聚合(Aggregate) | 表示整体与部分的关系.当某个实体聚合成 另一个实体时,该实体还可以是另一个实体的部分. |
|
组合(Combination) | 表示整体与部分的关系,组合比聚合 更加严格.当某个实体组合成另一个 实体时,二者具有相同的生命周期,例如 手臂和人之间是组合关系. |
|
泛化(Generalization) | 表示一个更泛化的元素与一个更具体的元素 之间的关系,与继承是同一个概念. |
|
实现(Realization) | 表示类与接口的关系,类实现接口. | ![]() |
依赖(Dependency) | 如果一个类的改动会影响另一个 类,则两个类之间存在依赖关系,一般而言,依赖是单向的. |
![]() |
UML2.0一共有13种图(UML1.5定义了9种,UML2.0增加了4种),分别是类图,对象图,构件图,部署图,活动图,状态图,用例图,时序图,协作图9种,以及包图,组合结构图,时间图,交互概览图4种.
图名称 | 解释 |
---|---|
类图(Class Diagrams) | 用于定义系统种的类 |
对象图(Object Diagrams) | 类图的一个实例,描述了系统在具体时间点上所包含的对象及各个对象之间的关系 |
构件图(Component Diagrams) | 一种特殊的UML图,描述系统的静态实现视图 |
部署图(Deployment Diagrams) | 定义系统中软硬件的物理体系结构 |
活动图(Activity Diagrams) | 用来描述满足用例要求所要进行的活动及活动时间的约束关系 |
状态图(State Chart Diagrams) | 用来描述类的对象的所有可能的状态和时间发生时,状态的转移条件 |
用例图(Usecase Diagrams) | 用来描述用户的需求,从用户的角度描述系统的功能,并指出各功能的执行者,强调谁在使用系统,系统为执行者完成哪些功能 |
时序图(Sequence Diagrams) | 描述对象之间的交互顺序,着重体现对象间消息传递的时间顺序,强调对象之间消息的发送顺序,同时显示对象之间的交互过程 |
协作图(Collaboration Diagrams) | 描述对象之间的合作关系,更侧重向用户对象说明哪些对象有消息的传递 |
包图(Package Diagrams) | 对构成系统的模型元素进行分组整理的图 |
组合结构图(Composite Structure Diagrams) | 表示类或者构建内部结构的图 |
时间图(Timing Diagrams) | 用来显示随时间变化,一个或多个元素的值或状态的更改,也显示时间控制事件之间的交互及管理它们的时间和期限约束 |
交互概览图(Interaction Overview Diagrams) | 用活动图来表示多个交互之间的控制关系的图 |
在UML 2.0的13种图中,类图(Class Diagrams)是使用频率最高的UML图之一.类图描述系统中的类,以及各个类之间的关系的静态视图,能够让我们在正确编写代码之前对系统有一个全面的认识.类图是一种模型类型,确切地说,是一种静态模型类型.类图表示类,接口和它们之间的协作关系,用于系统设计阶段.
在继承(Generalization,又叫作泛化)关系中,子类继承父类的所有的功能,父类所具有的属性,方法,子类都应该有.除了与父类一致的信息,子类中还包括额外的信息.
接口(包括抽象类)是方法的集合,在实现(Realization)关系中,类实现了接口,类中的方法实现了接口声明的所有方法.
组合(Combination)关系表示类之间整体与部分的关系,整体与部分有一致的生存期.一旦整体对象不存在,部分对象也将不存在,整体和部分是同生共死的关系.
聚合(Aggregate)关系表示类之间整体与部分的关系,成员对象是整体对象的一部分,但是成员对象可以脱离整体对象独立存在.例如,公交车司机和工作服,工作帽是整体与部分的关系,但是可以分开,没有共同的声明周期.工作服,工作帽可以穿,戴在别的司机身上,公交车司机也可以换别人的工作服,工作帽.
关联(Association)关系是类与类之间最常用的一种关系,表示一类对象与另一类对象之间有联系.组合,聚合也属于关联关系只是关联关系的类间关系比其他两种关系要弱.
关联关系有4种,双向关联,单向关联,自关联,多重性关联.例如汽车和司机,一辆汽车对应特定的司机,一个司机也可以开多辆车.
在多重性关联关系中,可以直接在关联直线上增加一个数字,表示与之对应的另一个类的对象的个数,具体含义如下表所示:
表示方式 | 含义 |
---|---|
1..1 | 仅一个 |
0..* | 零个或多个 |
1..* | 一个或多个 |
0..1 | 没有或只有一个 |
m..n | 最少m,最多n个(m<=n) |
依赖(Dependency)关系是一种"使用"关系,特定事物的改变有可能会影响到使用该事物的其他事物,当需要表示一个事物使用另一个事物时,使用依赖关系.在大多数情况下,依赖关系体现在某个类的方法使用另一个类的对象作为参数.例如: 汽车依赖汽油,如果没有汽油,则汽车无法行驶.
在这6种关系中,组合,聚合和关联的代码结构一样,可以从关系的强弱来理解,各类关系从强到弱依次是: 继承 > 实现 > 组合 > 聚合 > 关联 > 依赖.
分类 | 箭头特征 | 记忆技巧 |
---|---|---|
箭头方向 | 从子类指向父类 | 1. 定义子类需要通过extends关键字指定父类 2. 子类一定是知道父类的定义的,但父类并不知道子类的定义 3. 只有知道对方信息时才能指向对方 4. 箭头的方向是从子类指向父类 |
继承/实现 | 用线条连接两个类空心三角形箭头表示继承或实现 | 实线表示继承,是is-a的关系,表示扩展,不虚,很结实 虚线表示实现,虚线代表"虚"无实体 |
关联/依赖 | 用线条连接两个类; 普通箭头表示关联或依赖 |
1. 虚线表示依赖关系,临时用一下,若即若离,虚无缥缈,若有若无 2. 表示一种使用关系,一个类需要借助另一个类来实现功能 3. 一般一个类将另一个类作为参数使用,或作为返回值 4. 实线表示关联关系,关系稳定,实打实的关系,"铁哥们" 5. 表示一个类对象和另一个类对象有关联 6. 通常一个类中有另一个类对象作为属性 |
组合/聚合 | 用菱形表示; 像一个盛东西的器皿 |
1. 聚合:空心菱形,代表空器皿里可以放很多相同的东西,聚集在一起(箭头方向所指的类) 2. 整体和局部的关系,两者有独立的声明周期,是has-a的关系 3. 弱关系,消极的词,弱-空 4. 组合,实心菱形,代表器皿已经有实体结构的存在,生死与共 5. 整体与局部的关系,和聚合关系对比,关系更加强烈,两者具有相同的生命周期,contains-a的关系 6. 强关系,积极的词,强-满. |
时序图(Sequence Diagrams)描述对象之间消息的发送顺序,强调时间顺序.时序图是一个二维图,横轴表示对象,纵横表示时间,消息在各对象之间横向传递,按照时间顺序纵向排列,用箭头表示消息,用竖虚线表示对象生命线.
(1) 展示对象之间交互的顺序.将交互行为建模为消息的传递,通过描述消息如何在对象间发送和接收来动态展示对象之间的交互.
(2) 相对于其他的UML图,时序图更强调交互的时间顺序.
(3) 可以直观地描述并发进程.
时序图组成元素主要包括角色(Actor),对象(Object),生命线(Lifeline),控制焦点(Focus of Control)和消息(Message),其具体解释如下表所示:
元素 | 解释 | 图例 |
---|---|---|
角色 | 系统角色,可以是人,机器,其他系统,子系统 | ![]() |
对象 | 1. 对象的三种命名方式: 第一种方式包括对象名和类名 第二种方式只显示类名,即表示它是一个匿名对象 第三种方式只显示对象名不显示类名 2. 命名方式的选择 三种命名方式均可,那种最容易让阅读该时序图的人理解,就选哪种 3. 对象的排列顺序 对象的左右顺序并不重要,但是为了作图清晰整洁,通常应遵循以下两个原则,把交 互频繁地对象尽可能靠拢,把初始化整个交互活动的对象放置在最左侧 |
![]() |
生命线 | 在时序图中表示为从对象图标向下延伸的一条虚线,表示对象存在的时间 | ![]() |
控制焦点 | 又被称为激活期,表示时间段的符号,表示在这个时间段内对象将执行相应的操作可以理解为Java中一对大括号中的内容 | ![]() |
消息 | 消息一般分为同步消息(Synchronous Message),异步消息(Asynchronous Message)和返回消息(Return Message) 1. 消息发送者把控制传递给消息接收者,然后停止活动,等待消息接收者放弃或者返回控制,用来表示同步的意义. 2. 消息发送者通过消息把信号传递给消息接收者,然后继续自己的活动,不等待接收者返回消息或者控制.异步消息的接收者和发送者是并发工作的. 3. 返回消息表示从过程调用返回 |
组合片段(Combined Fragments)用来解决交互执行的条件和方式.它允许在时序图中直接表示逻辑组件,用于通过指定条件或子进程的应用区域,为任何生命线的任何部分定义特殊条件和子进程.组合片段共有13种,名称及含义如下:
类型 | 名称 | 说明 |
---|---|---|
Alt | 抉择 | 包含一个片段列表,这些片段包含备选消息序列.在任何场合下只发生一个序列.可以在每个片段中都设置一个临界来指示该片段可以运行的条件.else的临界指示其他临界都不为true时应运行的片段.如果所有临界都为false并且没有else,则不执行任何片段. |
Opt | 选项 | 包含一个可能发生或不可能发生的序列.可以在临界中指定序列发生的条件. |
Loop | 循环 | 片段重复一定次数.可以在临界中指示片段重复的条件.Loop组合片段具有Min和Max属性,它们指示片段可以重复的最小值和最大次数.默认值是无限制. |
Break | 中断 | 如果执行此片段,则放弃序列的其余部分.可以使用临界来指示发生中断的条件. |
Par | 并行 | 并行处理.片段中的事件可以交错. |
Critical | 关键 | 用来Par或Seq片段中.指示此片段中的消息不得与其他消息交错. |
Seq | 弱顺序 | 有两个或更多操作数片段.涉及同一生命线的消息必须按片段的顺序发生.如果消息涉及的生命线不同,则来自不同片段的消息可能会并行交错. |
Strict | 强顺序 | 有两个或更多操作数片段,这些片段必须按给定顺序发生. |
Consider | 考虑 | 指定此片段描述的消息列表.其他消息可发生在运行的系统中,但对此描述来说意义不大.在Message属性中键入该列表. |
Ignore | 忽略 | 指定此片段未描述的消息列表.这些消息可发生在运行的系统中,但对此描述来说意义不大.在Message属性中键入该列表. |
Assert | 断言 | 操作数片段指定唯一有效的序列.通常在Consider或Ignore片段中. |
Neg | 否定 | 此片段中显示的序列不得发生.通常在Consider或Ignore片段中. |
开闭原则(Open-Closed Principle,OCP)指一个软件实体如类,模块和函数应该对扩展开放,对修改关闭.所谓开闭,也正是对扩展和修改两个行为的一个原则.强调的是用抽象构建框架,用实现扩展细节,可以提高软件系统的可复用性及可维护性.开闭原则是面向对象设计中最基础的设计原则.它指导我们如何建立稳定灵活的系统,例如版本更新,我们尽可能不修改源码,但是可以增加新的功能.
在现实生活中,开闭原则也有体现.比如,很多互联网公司都实行弹性制工作时间,规定每天工作8个小时.意思就是说,对于每天工作8小时这个规定是关闭的,但是什么时候来,什么时候走是开放的.早来早走,晚来晚走.
实现开闭原则的核心思想就是面向抽象编程.
依赖倒置原则(Dependency Inversion Principle,DIP)指设计代码结构时,高层模块不应该依赖底层模块,二者都应该依赖其抽象.抽象不应该依赖细节,细节应该依赖抽象.通过依赖倒置原则,可以降低类与类之间的耦合性,提高系统的稳定性,提高代码的可读性和可维护性,并降低修改程序带来的风险.
单一职责原则(Simple Responsibility Principle,SRP)指不要存在一个以上导致类变更的原因.假设有一个Class负责两个职责,一旦发生需求变更,修改其中一个职责的逻辑代码,有可能会导致另一个职责的功能发生故障.这样一来,这个Class就存在两个导致类变更的原因.如何解决这个问题?我们就要分别用两个Class来实现两个职责,进行解耦.后期需求变更维护互不影响.这样的设计,可以降低类的复杂度,提高类的可读性,提高系统的可维护性,降低变更引起的风险.总体来说就是一个Class,Interface,Method只负责一项职责.
接口隔离原则(Interface Segregation Principle, ISP)指用多个专门的接口,而不使用单一的总接口,客户端不应该依赖它不需要的接口.这个原则知道我们在设计接口时,应当注意以下几点.
接口隔离原则符合"高聚合,低耦合"的设计思想,使得类具有很好的可读性,可扩展性和可维护性.在设计接口的时候,要多花时间思考,要考虑业务模型,包括还要对以后可能发生变更的地方做一些预判.所以,在实际开发中,我们对抽象,业务模型的理解是非常重要的.
迪米特法则(Law of Demeter, LoD)又叫作最少知道原则(Least Knowledge Principle, LKP),指一个对象应该对其他对象保持最少的了解,尽量降低类与类之间的耦合.迪米特法则主要强调和朋友交流,不和陌生人说话.出现在成员变量,方法的输入和输出参数中的类都可以被称为成员朋友,而出现在方法体内部的类不属于朋友类.
里氏替换原则(Liskov Substitution Principle, LSP)指如果对每一个类型为T1的对象O1,都有类型为T2的对象O2,使得以T1定义的所有程序P在所有对象O1都替换成O2时,程序P的行为没有发生变化,那么类型T2是类型T1的子类型.
定义看上去比较抽象,重新解释一下,可以理解为一个软件实体如果适用于一个父类,则一定使用于其子类,所有引用父类的地方必须能透明地使用其子类对象,子类对象能够替换父类对象,而程序逻辑不变.也可以理解为,子类可以扩展父类的功能,但不能改变父类原有的功能.根据这个理解,我们对里氏替换原则的定义总结如下:
合成复用原则(Composite/Aggregate Reuse Principle, CARP)指尽量使用对象组合(has-a)或对象集合(contains-a)的方式实现代码复用,而不是用继承关系达到代码复用的目的.合成复用原则可以使系统更加灵活,降低类与类之间的耦合度,一个类的变化对其他的类造成的影响相对较小.
继承,又称为白箱复用,相当于把所有实现细节暴露给子类.组合/聚合又被称为黑箱复用,对类似以外的对象是无法获取实现细节.我们要根据具体的业务场景来做代码设计,其实也都需要遵守面向对象编程(Object Oriented Programming, OOP)模型.
设计原则 | 一句话概括 | 目的 |
---|---|---|
开闭原则 | 对扩展开放,对修改关闭 | 降低维护带来的风险 |
依赖倒置原则 | 高层不应该依赖低层 | 更利于代码结构的升级扩展 |
单一职责原则 | 一个类只干一件事 | 便于理解,提高代码可读性 |
接口隔离原则 | 一个接口只干一件事 | 功能解耦,高聚合,低耦合 |
迪米特法则 | 不知道的不要知道 | 只和朋友交流,不和陌生人说话,减少代码臃肿 |
里氏替换原则 | 子类重写方法功能发生改变,不应该影响父类方法的含义 | 防止继承泛滥 |
合成复用原则 | 尽量使用组合实现代码复用,而不适用继承 | 降低代码耦合 |
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。