摘要:一文助你深入理解设计模式七大原则。

本文分享自华为云社区《零代码以“王者荣耀”为例解析设计七原则,助你面试拿“五杀”》,作者: 陈言必行 。

前言:

所有举例都是王者荣耀相关内容(不玩王者荣耀的同学,看起来稍费劲)。为了增加阅读兴趣和方便掌握这个七大原则,举例和原则的连接,我已经用尽毕生所学。陆陆续续写了一周还多,不喜勿喷哈~ 有收获的同学,记得点个赞再走…

PS:文中涉及到王者荣耀的相关名字部分使用绿色3号字标识,所以有了不知道是什么的小伙伴不用追溯,理解为一个装备名,英雄名或者直接理解为类名都是可以的。

一,单一职责原则

1.1 举例说明: 惩戒上单

时间:某休息日,地点:王者峡谷,人物:惩戒白起

版本描述:这个版本双烧流上单玩法很流行,这导致很多肉坦上单英雄都愿意携带惩戒,然后出红莲斗篷(日炎)。既能反野加快发育也能提高伤害加成…

情景再现:敌我双方拖至20分钟风暴龙王现身,可以说实力相当场面十分焦灼。到了抢夺风暴龙王一局定胜负的局面。话说我方双惩戒+白起长时间团战控制有更大的优势…

局内对话:

  • 打野:对面要打龙逼团了,我绕后找机会切对面射手法师,你们正面拉扯下,白起尝试抢龙
  • 辅助:白起一会打团你直接入场控制开团,我保双C(我方射手法师)
  • 上路白起:好的,龙马上快到斩杀血线了,大家准备… 我入场了,龙没抢到
  • 射手:没事没事,你找机会配合打野切对面鲁班,鲁班Si了就能打
  • 上路白起:打野准备切入,鲁班闪现了我大招距离不够,打野看你的了,鲁班没闪…

5S后,对面凭借风暴龙王Buff和鲁班输出,团灭我方。带好兵线就可以直接推掉我方水晶,取得胜利。

赛后复盘:

  1. 虽然白起携带惩戒,但是并没有抢到龙王。
  2. 也是因为携带惩戒,所以团站也没有控制到对面核心鲁班七号,导致输掉游戏。

但凡这两点能做到任意一点也不至于输掉游戏。

1.2 原则解析: 单一职责

其实大多数时候,一个位置的英雄简单一些,职责单一一些, 或许是更好的选择。这就和设计模式中的一大原则 —— 单一职责的道理是一样的。

就一个类而言,应该仅有一个引起它变化的原因,我们在写代码的时候,很自然的就会给一个类加各种各样的功能。比如我们写一款游戏,一般定义一个GameManager这样的类,于是我们就把各种各样代码,像处理逻辑算法啊,访问数据库啊什么的都写在这个类中。这就意味着,只要有需求改动,我们都需要修改这个游戏管理器,这其实是很差的写法,维护麻烦,不能复用,也缺少灵活性。

我们刚开始学习面向对象的时候,就知道面向对象的好处:可维护、可扩展、可复用、灵活性好。 所以这种写法是需要进行改正的。

如果一个类承担的职责过多,就等于吧这些职责耦合在一起,一个职责的变化可能削弱或者抑制这个类完成其他职责的能力。这种耦合会导致脆弱的设计,当变化发生时,设计会遭受到意想不到的破坏。

  • 单一职责的定义:

单一职责原则:就一个类而言,应该仅有一个引起它变化的原因。

二,开放封闭原则

2.1 举例说明: 黄刀由来

黄色打野刀上线也有几个版本了,简单猜测一下它的代码层面是如何实现的。

  • 既然是打野刀,那么也就有打野刀的通用属性(可对野怪释放)-- 可以通过继承实现。
  • 既然是新装备,那么也就有和其他打野刀不同的属性 – 创建自己的类实现。

像这种修改就符合开闭原则。对扩展开启,对修改封闭。这时候你可能在想,我这不是说一堆废话嘛。新添加了一个装备可不要扩展吗,怎么也不会在红色打野刀类中去写黄色打野刀的逻辑啊…

确实是这样,可是你想过没有,这是在一个成熟的框架下去添加新装备。若这是刚开始开发的程序呢?我们实现的时候不会将所有的二级打野刀都写在一个类中,然后使用属性或者枚举来区分当前使用的打野刀是什么,然后进行相应的逻辑处理…

2.2 原则解析: 开闭原则

因为我们在最初写代码的时候,都假设需求不会产生改变。当需求变化时,我们就创建抽象来隔离以后发生同类的变化。 比如原来王者中只有两种类型的打野刀:一个是物理伤害,一个是法术伤害的。其他各种属性都一样,那么此时我们写代码的时候完全可能将这两个打野刀写在一个类中。后来又来一个打野刀,它也是物理伤害的,但是属性从加伤害变成加防御了。

那么此时我们就需要考虑未来游戏平衡会不会再添加新的打野刀,会不会修改现有单一打野刀的属性和数值…这时候我们的原来写的一个类中实现的两个打野刀,就会自然的演变成一个打野刀基类,两个子类继承的形式。进而有了后续添加打野刀时的添加方式。

我们在做任何应用的时候,都不要指望一开始时需求确定,就再也不会有修改。既然需求一定会变化,那么如何在面对需求变化时,使得我们的程序可以相对容易的修改,不至于说,新需求一来,我们要删除原来部分代码,重新写一套。这就是开放封闭原则存在的意义。

对于开发时呈现出频繁变化的那些部分做出抽象,然而,对于程序中的每个部分都可以的进行抽象同样是一种不好的做法。拒绝不成型的抽象和抽象本身一样重要。

开放-封闭原则是面向对象设计的核心所在。遵循这个原 则可以带来面向对象技术所声称的巨大好处,也就是可维护、可扩 展、可复用、灵活性好。

  • 开闭原则的定义:

开放-封闭原则:是说软件实体(类,模块,函数等等)应该是可以扩展,但是不可修改。

三,里氏代换原则

3.1 举例说明: 吸血之镰

吸血之镰俗称小吸血刀,可合成装备如下:

由上图我们可以看到小吸血刀的属性:

  • +10 物理攻击
  • +8% 物理吸血

当我们点击它可合成装备时,可以看到三个装备的属性值都是包含 +物理攻击 和 +百分比物理吸血 的。这就是说明,大件装备由小件装备合成,并且继承了小件装备的属性值(多出来的部分时大件私有的)。

在游戏中不管你此时购买了末世,泣血,制裁这三个装备中的哪一个,你都获得了其父类小吸血刀的属性值。在程序的角度讲使用到小吸血刀(父类)的代码完全可以被这三个装备(子类)任意一个去替换,并且不会对游戏逻辑产生影响,这就是里氏代换原则了。

3.2 原则解析: 里氏代换

进一步描述:

子类对象能够替换程序中的父类对象出现的任何对象,并且保证原来的程序逻辑行为不变及正确性不被破坏。这么一说有点类似多态,多态是面向对象编程的一大特性,也是面向对象编程语言的一种语法。他是一种代码实现思路。而里氏替换是一种设计原则,是用来指导继承关系中子类该如何设计,子类的设计要保证在替换父类的时候,不改变原有程序逻辑以及不破坏原有程序的正确性。

回到举例:

若在我们上面的举例中有一个小吸血刀类中(父类)GetAttribute()方法可以返回当前装备的属性,此时父类返回【 +10物理攻击,+8%物理吸血】;在大吸血刀类中(子类)GetAttribute()返回【 +100物理攻击,+25%物理吸血】,那么此时这个子类的设计就违背了里氏替换原则。

一个软件实体如果使用的是一个父类的话,那么一定适用于其子类,而且察觉不出父类对象和子类对象的区别;也就是说,在程序里面,把父类都替换成它的子类,程序的行为没有变化;简单地说,子类型必须能够替换掉它们的父类型。

  • 里氏原则的定义:

里氏代换原则:子类型必须能够替换掉他们的父类型。

四,迪米特法则

又称:最少知道法则

4.1 举例说明: 妲己抓人

时间:某休息日,地点:王者峡谷,人物:亚瑟,妲己

妲己在中路清完线,来上路帮助亚瑟抓人。

妲己一连发起三个快捷消息:

  1. 发起进攻
  2. 二技能已经好了
  3. 大招还有3秒

亚瑟回复快捷消息:

  • 收到

3秒后,妲己走到上路草丛埋伏。亚瑟卖血假装打不过,撤向妲己所在草丛,妲己一套二三一,配合亚瑟收下对面上路人头。

对于亚瑟来说,他只知道妲己在准备来上路抓人,技能马上好了,这两个消息,他并不知道妲己技能当前加点等级,也不知道妲己还差多少钱可以出下个装备。这些妲己的 “ 内部实现 ",亚瑟都不知道,他也不需要知道。这就是迪米特法则。

4.2 原则解析: 迪米特法则

“迪米特法则首先强调的是前提是在类的结构设计上,每一个类都应当尽量降低成员的访问权限;也就是说,一个类包装好自己的private状态,不需要别的类知道的字段或行为就不要公开”

迪米特法则其根本思想是强调了类之间的松耦合。

  • 迪米特法则的定义:

迪米特法则:如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用。如果其中一个类需要调用另一个类的某个方法的话,可以通过第三者转发这个调用。

五,接口分离原则

5.1 如何理解接口隔离原则?

理解“接口隔离原则”的重点是理解其中“接口”二字:

  • 若把“接口”理解为面向对象中的接口,那接口的设计要尽量单一,不要让实现类有用不到的接口函数。
    比如说:A类实现I接口,I接口中有X(),Y()两个函数;若A类只需要用X(),那么这样的设计是不合理的。
  • 若把“接口”理解为一组接口的集合,可以是某个类库的接口。如果使用的类只需要调用其中的部分接口,那么我们需要将这部分接口隔离出来,单独给部分调用者使用。

5.2 与单一职责原则的区别

  • 单一职责针对的是模块、类、接口的设计。接口隔离原则相对于单一职责原则,一方面更侧重接口的设计,另一方面它的思考角度也是不同的
  • 接口隔离原则则提供了一种判断接口的职责是否单一的标准:通过调用者如何使用接口间接地判定。如果调用者只使用部分接口或部分接口的功能,那接口设计的就不够单一。

接口隔离原则:不应该强迫对象依赖它不需要的接口。

六,依赖倒置原则

6.1 举例说明: 电脑主板

昨天公司美术妹子的电脑用着用着突然蓝屏了,来找我帮忙看看咋回事。根据我的经验是内存条坏了,于是我打开机箱拆下内存条,更换插槽各种操作,最终确定了就是其中的一个内存条坏了。换了个新的内存条,电脑成功启动。

能这么轻松的解决问题还是要归功于PC的易插拔设计,不管是内存、显卡、硬盘等任何部件坏了,我们只需更换坏的那个就可以了。**这种易插拔在面向对象中就是强内聚,低耦合。

** 因为无论是那个厂家制造的这内存条,也不管它的内部实现是什么样的,它最终都需要支持主板的插槽。这就是针对接口设计。若针对实现设计,那么很打可能我们的内存条坏了,也需要更换对应的主板。

6.2 原则解析: 依赖倒置

依赖倒置设计理念: 相对于细节的多变性,抽象的东西要文档的多。以抽象为基础搭建的架构比细节为基础搭建的架构要稳定的多。依赖倒置的中心思想是面向接口编程。

面向过程开发时,为了使得常用的代码可以复用,一般都会吧这些常用的代码写成许许多多函数的程序库,这样我们在做新项目时,去调用这些低层的函数就可以了。

  • 依赖倒置的定义:

依赖倒置原则:
A.高层模块不应该依赖底层模块。两个都应该依赖抽象。
B.抽象不应该依赖细节。细节应该依赖抽象。

七,合成/聚合复用原则

之前我的理解是:合成复用 和 聚合复用 是两个名字一个意思。后来具体学习了才知道,其实并不是这样,可以说这是两种相近的设计模式。到底是怎么回事? 往下看看吧~

7.1 举例说明: 兵线队列

合成和聚合都是关联的特殊种类:

  • 聚合表示一种弱的‘拥有’关系,体现的是A对象包含B对象,但B对象不是A的对象的一部分
  • 合成则表示一种强的‘拥有’关系,体现了严格的部分和整体的关系,部分和整体的生命周期是一致的。

比方说:王者荣耀中的兵线,每一波兵线都由多个小兵组成,每个小兵都属于一队兵线,一队兵线和多个小兵是聚合关系。 而每个小兵都有一个的武器(攻击类),武器和小兵是部分与整体的关系,并且他们的生命周期是相同的,于是小兵和武器就是合成关系。

7.2 原则解析: 合成/聚合复用

合成/聚合复用的好处:优先使用对象的合成/聚合将有助于我们保存封装每个类,并被集中在单个任务上。这样类和类的继承层次会保持较小规模,并且不太可能增长为不可控制打庞然大物。

  • 合成/聚合复用原则的定义:

合成/聚合复用:尽量使用合成/聚合,尽量要使用类的继承。

点击关注,第一时间了解华为云新鲜技术~

零代码以“王者荣耀”为例解析设计七原则相关推荐

  1. 零代码以“王者荣耀”为例解析设计七原则,助你拿下面试

    零代码以"王者荣耀"为例解析设计七原则,助你面试拿"五杀" 前言: 一,单一职责原则 1.1 举例说明: 惩戒上单 1.2 原则解析: 单一职责 二,开放封闭原 ...

  2. python玩王者荣耀皮肤_Python爬虫:十几行代码下载王者荣耀所有皮肤

    访问,一键创建你的人工智能项目作者 | 王强 来源 | C与Python实战 起因:前两天在公众号上看到一篇文章内容就是爬取王者荣耀的皮肤,但是内容太大概了,如果跟着他做肯定做不出来,所以我打算自己做 ...

  3. 使用YOLOV5训练自己的数据集(以王者荣耀为例)

    注:本文只是记录笔者使用yolov5训练自己的数据集的实现过程,不讲原理,如果想学原理请移步点击量比较高的大佬博客,笔者只是大二本科生,如有问题还请多多指教! 一,什么是yolov5? "Y ...

  4. 以王者荣耀为例,教你将一天的时间用成28小时

    第一财经周刊>携手优衣库发布<2018年中国Z世代理想生活报告>中提到: 在受访的95后中,74%的人把闲暇时间分配给了"学习和课外自我充电":对于理想生活的时间 ...

  5. 复制部分网页源代码到本地HTML文件,使用Python ==> pqQuery库 导入本地html文件,实现6行代码输出王者荣耀所有人物角色姓名

    前言:本次使用Google浏览器测试(不同浏览器会有些许差异,但是逻辑相通) 1.打开 英雄资料列表页-英雄介绍-王者荣耀官方网站-腾讯游戏 :https://pvp.qq.com/web201605 ...

  6. 从王者荣耀看设计模式(七.装饰者模式)

    ##从王者荣耀看设计模式(装饰者模式) 一.简介 王者荣耀中,角色的"伤害值"和"生命值"是很重要的概念.为了保证游戏的胜利,玩家会通过在游戏开始前配置合适的游 ...

  7. 《游戏系统设计十》从零复刻王者荣耀活动系统,策划都能看得懂的活动系统,源码奉送

    目录 1.活动类型 2.需求 3.文件下载 4.文件解压 5.json的读取 6.模块组织方式

  8. 王者荣耀——bat批处理文件,自动刷金币版(脱胎于30行Python代码刷金币版),Windows双击即可运行!

    参考<30行Python代码刷王者荣耀金币>:https://segmentfault.com/a/1190000012520431 1.源代码 以下是源代码部分,全部复制到文本文档, 用 ...

  9. 符号_王者荣耀龙符号名字怎么弄 打龙符号名字代码复制大全

    [闽南网] 王者荣耀角色名字带上特殊符号会显得更加酷炫,所以许多玩家都为自己的名字增添了不一样的风采,那么王者荣耀龙符号名字怎么打?下面小编为您带来王者荣耀龙符号名字代码. 王者荣耀龙符号名字怎么打? ...

最新文章

  1. html页面缓存纪txt,cdn缓存的html静态页未更新小记
  2. shanghai hongqiao railway station
  3. 分享2018年陆陆续续读过的书-附书单
  4. Unity Android解决信息流广告关闭报错
  5. 数据结构与算法学习笔记之 从0编号的数组
  6. 【转】谈谈c#中异步编程模型的变迁**
  7. spark的数三角形算法_Spark任务调度概述
  8. IT工具与知识管理理念的紧密结合----A咨询公司简介
  9. typescript之prototype
  10. log4j-over-slf4j与slf4j-log4j12共存stack overflow异常
  11. 经典人生感悟 看看你少了那一条
  12. 6.剑指Offer --- 面试中的各项能力
  13. Arduino无法下载,重刷Bootloader后解决问题
  14. KeyCloak实现单点登录说明
  15. 又是被自己菜哭的一天。。
  16. 基于遗传算法的TSP和MTSP问题求解(python)
  17. oracle 范鑫_快速理解数据库中的索引(Indexes in Database)
  18. 【高数】变上限积分的等价无穷小替换
  19. 如何云储存服务实现视频存储
  20. 冯氏结构、哈佛结构、超级哈佛结构之间的异同

热门文章

  1. 实践 | Centos 7搭建LVS+Keepalived高可用Web服务群集群
  2. JavaScript之call,bind,apply方法及 this 的用法辨析
  3. HTML5 address元素
  4. es6 Class 的 Generator函数
  5. 作为函数的mixin
  6. Git笔记(4) 获取仓库
  7. android 语音阅读软件,语音阅读器APP
  8. java 反射深度克隆_C# 使用反射来实现对象的深度复制方法
  9. 有了代码怎么用python爬虫_python实现简单爬虫功能
  10. php中strtotime的意思,PHP中strtotime