大家好,我是小菜,一个渴望在互联 行业做到蔡不菜的小菜。可柔可刚,点赞则柔,白嫖则刚!
死鬼~看完记得给我来个三连哦!
一、UML 图
不要觉得奇怪为什么不讲软件设计原则而说到了 UML 图,因为软件设计原则和软件设计模式中你讲到最多的便是利用类图来表示 类与类之间的关系,因此我们需要 先会看,再会理,最后再来写!
1. 什么是 UML
统一建模语言(Unified Modeling Language,UML),是用来设计软件的可视化建模语言,它的特点是简单、统一、图形化、能表达软件设计中的动态与静态信息。
UML 从目标系统的不同角度出发,定义了用例图、类图、对象图、状态图、活动图、时序图、协作图、构件图、部署图等 9 种图。而我们来重点了解一下 类图。
2. 类图
1)类图的概念
类图(Class disgram)是显示了模型的静态结构,特别是模型中存在的类、类的内部结构以及它们与其他类的关系等。类图不显示暂时性的信息,类图是面向对象建模的主要组成部分。
2)类图的作用
类图是一种静态的结构图,描述了系统中类的集合、类的属性和类之间的关系,可以简化对系统的理解。
3)类图的表示
类图的表示是使用包含类名(className)、属性(field)和方法(method)且带有分割线的矩形来表示,格式如下:
我们可以看到 属性/方法 前面存在 + / – ,他们表示了这个属性或方法的可见性,表示可见性的符 有三种,如下:
- + : 表示 public
- – : 表示 private
- # : 表示 protected
从上面的示例中我们可以总结出:
- 属性的完整表示方式是:可见性 名称 : 类型 [ = 缺省值]
- 方法的完整表示方式是:可见性 名称(参数列表) [ : 返回类型]
中括 里的内容是可选的
也可以将类型放在变量名前面,返回值类型放在方法名前面
4)类图的关系
1. 关联关系
关联关系是对象之间的一种引用关系,用于表示一个类对象与另一个类对象之间的联系。比如老师和学生,学生与课程,校长与学校。关联关系是类与类之间最常用的一种关系,分为 一般关联关系,聚合关系和组合关系
一般关联关系又分为: ,,
- 单向关联
双向关联通俗的意思就是:。从上图中我们可以看出:双方类中各自持有对方类型的成员变量。在 Company(公司类) 中持有一个 **Employee(员工类)**的集合,表示一个公司有可以有多个员工,而在 Employee(员工类) 中持有一个 Company(公司类) 的成员变量,表示这个员工所属于哪个公司。
需要注意的是,双向关联的连线与单向关联有所不同。双向关联是用一个 不带箭头的直线 表示。
- 自关联
注: 聚合关系是使用 带空心菱形的实线 表示的,特别需要注意菱形的方向,菱形是指向整体的
3. 组合关系
既然聚合关系是一种 的关系,那有没有那种 的关系呢定是有的,那就是聚合关系的加强版—组合关系。这是一种更加强烈的聚合关系。
在组合关系中,整体对象可以控制部分对象的生命周期,一旦整体对象不存在,部分对象也将不存在,部分对象不能脱离整体对象而存在,有点 的内味了。这就好像我们头和嘴的关系,如果头不存在了,那么嘴也就不存在了。
注: 依赖关系是使用 带箭头的虚线来表示,箭头从使用类指向被依赖的类。
5. 继承关系
继承关系是对象之间耦合度最大的一种关系,表示一般与特殊的关系,是父类与子类之间的关系,是一种继承关系。比如 Student 类 和 Teacher 类 都是 Person 类的子类。
注: 实现关系是使用 带空心三角箭头的虚线来表示,箭头从实现类指向接口。
微信搜:小菜良记
更多干货值得关注
二、软件设计原则
上面铺垫了那么多知识,主角终于可以上场了。我们也不卖关子了,直接来看下我们将要了解到的软件设计原则:
2. 里氏代换原则
里氏代换原则:任何基类可以出现的地方,子类一定可以出现。简单来说就是子类可以扩展父类的功能,但不能改变父类原有的功能,也就是子类继承父类时,除了添加新的方法完成新增功能外,尽量不要重写父类的方法。
里氏代换原则也是面向对象设计中最基本的原则之一,通俗意思就是父类总能被子类替代。如果我们通过重写父类的方法来完成新的功能,这样写起来虽然比较简单,但是整个继承体系的可复用性会比较差,特别是运用多态比较频繁时,程序运行出错的概率会非常大。
示例:正方形是一个特殊的长方形,只不过是正方形的长宽都一样,那我们就用反证法来试一下是否符合里氏代换原则
:
我们可以看到有个长为10,宽为15的长方形,我们也成功实现了功能,扩容后的长方形长为16,宽为15。根据里氏代换原则,我们如果传入的是 正方形类也是可以实现这个功能的,我们继续来试一下:
我们在控制台等了许久,发现并没有输出结果,直到栈溢出。这是长一直与宽相等,导致退出不了循环。那么这个时候我们得出结论,这种设计是不符合的,因此这种设计是错误的。所以我们平时在设计系统的时候,就需要考虑我们设计的父子类是否符合,那么根据以上例子我们可以作出改进,既然 长方形类 不适合做 正方形类 的子类,那我们是否应该考虑抽象出一个 四边形类 出来,来作为两个类的父类。
:
看完代码我们改变的只有增加了 四边形类 和修改了 正方形类,这样子我们使用扩容方法的时候需要传的是 长方形类,而 正方形类 不继承与 长方形类,扩容这个方法不适用,因此满足了
3. 依赖倒转原则
依赖倒转高层模块不应该依赖底层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。
简单来说依赖倒转的核心就是对抽象进行编程,不要对实现进行编程,这样就会降低客户与实现模块之间的耦合。
示例:我们如果要组装一台电脑,组装电脑需要用到的配件有硬盘,内存和CPU,每个配件都有不同的品牌以供选择,我们这里选择希捷的硬盘,英特尔的CPU,金士顿的内存,图示如下:
根据运行结果我们计算机也顺利组装成功,但是目前看起来好像是没问题,如果我们想要换个品牌的 CPU 或者 内存条,我们除了增加一个 对应品牌的类之外我们是不是还要修改 Computer 类,刚看完上部分的小伙伴肯定马上意识到这不就违反了 吗,真是瞎胡闹。
那既然这种设计是错误的,我们就按照 依赖倒装原则 来改进一下:,我们需要修改 Computer 类,让Computer类 依赖抽象(各个配件的接口),而不是依赖于各个组件具体的实现类。图示如下:

代码中我们只需要修改 Computer 类 和增加三个配件的主接口,让子品牌分别实现对应的接口即可:
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!