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

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: 面试设计原则还在死记硬背?一文助你深入理解设计模式七大原则。

前言:

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

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


一,单一职责原则

1.1 举例说明: 惩戒上单

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

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

1.1

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

局内对话:

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

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

赛后复盘:

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

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

1.2 原则解析: 单一职责

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

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

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

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

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

二,开放封闭原则

2.1 举例说明: 黄刀由来

2.1

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

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

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

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

2.2 原则解析: 开闭原则

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

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

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

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

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

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

三,里氏代换原则

3.1 举例说明: 吸血之镰

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

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

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

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

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

3.2 原则解析: 里氏代换

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

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

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

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

四,迪米特法则

又称:最少知道法则

4.1 举例说明: 妲己抓人

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

妲己在中路清完线,来上路帮助亚瑟抓人。
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.1

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

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

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

  • 合成/聚合复用原则的定义:
合成/聚合复用:尽量使用合成/聚合,尽量不要使用类的继承。

  文中有两个原则的举例说明,我实在是没想出怎么用王者荣耀相关内容举例分析。若你有好的想法欢迎评论区补充。

学习完了休息一下吧,走打王者去~
王者

相关文章
|
4天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
16 2
|
4天前
|
存储 网络协议 安全
30 道初级网络工程师面试题,涵盖 OSI 模型、TCP/IP 协议栈、IP 地址、子网掩码、VLAN、STP、DHCP、DNS、防火墙、NAT、VPN 等基础知识和技术,帮助小白们充分准备面试,顺利踏入职场
本文精选了 30 道初级网络工程师面试题,涵盖 OSI 模型、TCP/IP 协议栈、IP 地址、子网掩码、VLAN、STP、DHCP、DNS、防火墙、NAT、VPN 等基础知识和技术,帮助小白们充分准备面试,顺利踏入职场。
17 2
|
15天前
|
存储 NoSQL MongoDB
MongoDB面试专题33道解析
大家好,我是 V 哥。今天为大家整理了 MongoDB 面试题,涵盖 NoSQL 数据库基础、MongoDB 的核心概念、集群与分片、备份恢复、性能优化等内容。这些题目和解答不仅适合面试准备,也是日常工作中深入理解 MongoDB 的宝贵资料。希望对大家有所帮助!
|
21天前
|
存储 安全 Java
系统安全架构的深度解析与实践:Java代码实现
【11月更文挑战第1天】系统安全架构是保护信息系统免受各种威胁和攻击的关键。作为系统架构师,设计一套完善的系统安全架构不仅需要对各种安全威胁有深入理解,还需要熟练掌握各种安全技术和工具。
59 10
|
20天前
|
缓存 前端开发 JavaScript
"面试通关秘籍:深度解析浏览器面试必考问题,从重绘回流到事件委托,让你一举拿下前端 Offer!"
【10月更文挑战第23天】在前端开发面试中,浏览器相关知识是必考内容。本文总结了四个常见问题:浏览器渲染机制、重绘与回流、性能优化及事件委托。通过具体示例和对比分析,帮助求职者更好地理解和准备面试。掌握这些知识点,有助于提升面试表现和实际工作能力。
54 1
|
20天前
|
前端开发 JavaScript 开发者
揭秘前端高手的秘密武器:深度解析递归组件与动态组件的奥妙,让你代码效率翻倍!
【10月更文挑战第23天】在Web开发中,组件化已成为主流。本文深入探讨了递归组件与动态组件的概念、应用及实现方式。递归组件通过在组件内部调用自身,适用于处理层级结构数据,如菜单和树形控件。动态组件则根据数据变化动态切换组件显示,适用于不同业务逻辑下的组件展示。通过示例,展示了这两种组件的实现方法及其在实际开发中的应用价值。
28 1
|
1月前
|
架构师 关系型数据库 MySQL
MySQL最左前缀优化原则:深入解析与实战应用
【10月更文挑战第12天】在数据库架构设计与优化中,索引的使用是提升查询性能的关键手段之一。其中,MySQL的最左前缀优化原则(Leftmost Prefix Principle)是复合索引(Composite Index)应用中的核心策略。作为资深架构师,深入理解并掌握这一原则,对于平衡数据库性能与维护成本至关重要。本文将详细解读最左前缀优化原则的功能特点、业务场景、优缺点、底层原理,并通过Java示例展示其实现方式。
71 1
|
1月前
|
机器学习/深度学习 人工智能 算法
揭开深度学习与传统机器学习的神秘面纱:从理论差异到实战代码详解两者间的选择与应用策略全面解析
【10月更文挑战第10天】本文探讨了深度学习与传统机器学习的区别,通过图像识别和语音处理等领域的应用案例,展示了深度学习在自动特征学习和处理大规模数据方面的优势。文中还提供了一个Python代码示例,使用TensorFlow构建多层感知器(MLP)并与Scikit-learn中的逻辑回归模型进行对比,进一步说明了两者的不同特点。
64 2
|
1月前
|
存储 搜索推荐 数据库
运用LangChain赋能企业规章制度制定:深入解析Retrieval-Augmented Generation(RAG)技术如何革新内部管理文件起草流程,实现高效合规与个性化定制的完美结合——实战指南与代码示例全面呈现
【10月更文挑战第3天】构建公司规章制度时,需融合业务实际与管理理论,制定合规且促发展的规则体系。尤其在数字化转型背景下,利用LangChain框架中的RAG技术,可提升规章制定效率与质量。通过Chroma向量数据库存储规章制度文本,并使用OpenAI Embeddings处理文本向量化,将现有文档转换后插入数据库。基于此,构建RAG生成器,根据输入问题检索信息并生成规章制度草案,加快更新速度并确保内容准确,灵活应对法律与业务变化,提高管理效率。此方法结合了先进的人工智能技术,展现了未来规章制度制定的新方向。
34 3
|
1月前
|
SQL 监控 关系型数据库
SQL错误代码1303解析与处理方法
在SQL编程和数据库管理中,遇到错误代码是常有的事,其中错误代码1303在不同数据库系统中可能代表不同的含义

推荐镜像

更多