在复杂的软件开发中,设计模式作为一套通用的解决方案,能够有效提高系统的可维护性、扩展性以及灵活性。以下是设计模式的一些介绍和应用场景:
创建模式:
1.工厂模式
分为简单工厂模式,工厂方法模式和抽象工厂模式。
何时使用工厂模式:需要客户端创建对象部分代码要求不能修改时,使用工厂模式,但是实际情况下如果创建对象部分代码支持修改,则可以不适用工厂模式,提高开发效率。
工厂方法模式对比简单工厂模式解决了什么问题:省去了工厂类的if-else,将创建方法的具体实现交给工厂类的子类去实习,扩展时避免对工厂基类(接口)的修改。(理解:复杂度提升后,即便使用工厂方法模式,设置工厂实例的地方也要大量添加ifelse,此时多人都要修改这个地方,依旧免除不了冲突。我认为相比使用工厂方法模式,采用反射、attribute特性(c#)能更好的解决团队开发冲突问题,在个人开发中要提取客户端的ifelse直接使用简单工厂即可)
2.抽象工厂模式
工厂方法模式和抽象工厂模式的区别:区别不大,主要体现在工厂基类的创建方法数量(产品分类数量)。
3.单例模式
理解:单例模式用于确保整个项目中只能创建唯一一个实例(而不是为了调用方便可以四处产生依赖)
4.建造者模式
构造方法初始化参数过多时考虑使用建造者模式链式调用,但是如果构造方法中的每个参数都是必须初始化的,链式调用虽然直观,但是很容易产生遗漏,可以通过在链式调用的最后添加build方法来进行参数设置验证和初始化处理:builder.stage1().set_cpu("Intel i9").set_ram("32GB").next_stage().set_hard_disk("1TB SSD").set_monitor("27 inch 4K").build()
5.原型模式
(理解:原型模式的克隆方法能够简化对象创建的大量属性赋值等初始化操作)
结构模式:
6.适配器模式
(理解:继承当前系统需要的接口,并组合第三方插件的对象,以实现当前系统对第三方插件的调用)
7.装饰器模式
-
继承统一接口,保证方法一致性
-
组合接口对象,动态添加功能
-
通过层层包装实现功能的叠加
(理解:装饰器模式通过继承接口以规范方法实现,组合接口的实例化对象以实现功能的额外添加或多个装饰器功能组合添加,虽然采用动态组合复用大大减少了代码量,但是由于是动态添加的所以十分抽象,很难确切的知道当前装饰器中到底包含了哪些功能)
8.代理模式
和装饰器模式的区别:代理模式和装饰器模式在代码实现上极其相似,都采用了继承+组合的实现,但装饰器主要体现在附加功能,代理主要体现在对象的访问控制和权限验证,避免了验证逻辑的重复实现。
示例:换个实际的场景,包含角色,武器,和根据角色等级判断是否能穿戴武器,此时,我有多种选择,可以在角色穿戴方法中判断是否能穿戴武器,也能额外写个武器代理在代理中判断,此时为了保证判断代码便于修改(防止多处修改),因此我们应该将判断逻辑写在武器代理中
9.外观模式
理解:外观模式(门面模式)是在某个复杂系统中包含很多子系统时,在父系统中提供调用子系统功能的方法,实现外部功能和子系统之间的解耦。
简单案例:角色身上可以装备不同武器,角色的攻击力取决于使用的武器的攻击力,此时角色应当提供获取攻击力的方法并在方法中调用武器获取攻击力的方法,以供外部调用。
10.桥接模式
理解:桥接模式主要适用于系统中存在多个维度的不同类型的情况,为了用组合替代继承(防止每几种维度的组合都实现一个子类,导致子类爆炸),用抽象类组合接口的形式,实现组合使用各个维度的实例。
简单的例子:主角和敌人都能使用各自的武器(武器可能相同),此时给主角敌人提供一个公共的父类角色类,给不同的武器提供一个公共的武器接口,此时角色类组合武器接口,以达到主角和敌人自由切换各自武器的目的,可以只用WeaponA、WeaponB而不用分成PlayerWeaponA、PlayerWeaponB、EnemyWeaponA、EnemyWeaponB如此多的子类。(如果玩家和敌人有着各自独立允许使用的武器列表,可以引入代理模式的武器代理来控制武器的穿戴)
11.组合模式
理解:组合模式强调单个对象组合统一接口的子对象列表这种树形的结构(感觉类似ecs架构),并且可以通过一个统一方法来调用所有的子对象,避免了不同逻辑的处理,交给子对象的子类去实现不同逻辑。
12.享元模式
理解:享元模式的主要思想就是分离一个类的共用部分和各自独立的部分,共用部分可以借助static关键字或者维护一个唯一的享元对象,实现部分可以将独立的部分单独封装成一个Instance类实现或者依靠共享部分的static即可节约内存。
关系模式:
13.策略模式
策略模式用于在使用处消除ifelse,当算法随时需要修改变更时适合使用,但是选择策略对象是依然存在ifelse,要隔离ifelse可同时使用工厂模式。
14.模板方法模式
理解:模板方法模式通常用于一系列具有相同操作流程的子类,此时可以提取出基类,将固定步骤封装在基类中,然后子类有不同实现的地方基类用虚方法或抽象方法交给子类去重新实现,以提高复用性。举个简单例子,不同的敌人具有相同的ai逻辑,但是攻击手段不同(可能有近战、远程单位),此时可以提取出EnemyBase积累,将相同的ai逻辑交给基类实现,具体的攻击、受击、死亡方法作为抽象方法交给子类去实现。
15.观察者模式
理解:由于控制层依赖底层系统,可以直接调用,所以底层系统不能反过来再依赖控制层(构成循环依赖),所以只能通过委托、事件回调等方式通知控制层,此时适合使用观察者模式实现底层系统或者组件向控制层发送事件回调。
16.迭代器模式
理解:迭代器模式用于不暴露集合内部实现的情况下实现顺序访问,但是很少使用,因为现在主流的编程语言都支持foreach访问容器。
17.责任链模式
理解:责任链模式用于存在复杂ifelse并且需要按照顺序尝试处理的情况,可以将之拆解得易于维护,也可以用于处理按照链式进行调用。
18.命令模式
理解:命令模式主要用于撤销重做功能得实现,也可用于将一系列行为进行封装,使代码更简洁。
19.备忘录模式
理解:备忘录模式用于获取和恢复对象的一些属性,可用于游戏中存档点的实现。
20.状态模式
理解:当对象具有多种状态时,使用状态模式可以管理各种状态的进入、退出、何时跳转到另一种状态,游戏开发中有限状态机(fsm)就是状态模式的一种实现,与其将状态代码散列在各处,用状态模式可以使得逻辑更加清晰。
21.访问者模式
理解:用于将对象操作从对象类中提取出来(由于这些操作经常改动),交给其他要访问对象的类去实现,比如将角色受伤的方法转移到技能类中,在技能的攻击方法中传入角色对象并在其中进行处理。
22.中介者模式
理解:中介者模式解除了对象之间的依赖,比如在游戏中引入一个战斗系统,在这个系统中传入玩家和当前敌人,并执行战斗过程,这一方式就是运用了中介者模式。
23.解释器模式
理解:一个字符串中所有内容都要按照一定规则解析,如自定义一个伤害计算公式"(atk-def)**dmgFactor**critFactor",然后在代码中传入所需参数并解析公式并带入计算获得伤害数值,这一过程属于解释器模式。