技术笔记(13)设计模式

技术笔记(13)设计模式

  • 学习笔记:

    • 设计原则:

      • 作用:让软件系统更加稳定,容易维护且具有一致性

      • 开闭原则

        • 定义:对扩展开放,对修改关闭
        • 关联:接口
        • 总结:面对需求,对程序的改动是通过增加新代码进行的,而不是改变原有的代码
      • 依赖倒置原则

        • 定义:

          • 高层模块不应该依赖低层模块,它们都应该依赖抽象。抽象不应该依赖于细节,细节应该依赖于抽象。
          • 要针对接口编程,不要针对实现编程。
        • 关联:通过接口去声明某个对象和调用

        • 常用实现方式之一是在代码中使用抽象类,而将具体类放在配置文件中

      • 里氏代换原则

        • 实现开闭原则重要方式之一,在程序中尽量使用积累类型来对对象进行定义,而在运行时再确定其子类类型,用子类对象来替换父类对象。
        • 父类替换成子类可以,子类替换成父类不行
      • 单一职责原则

        • 定义:

          • 一个对象只包含单一的指责,并且该职责被完整地封装在一个类中
          • 就一个类而言,应该仅有一个引起它变化的原因
      • 接口隔离原则

        • 定义:

          • 客户端不应该依赖那些他不需要的接口
          • 一单一个接口太大,需要把它分割成一些更细小的接口,使用该接口的客户端仅需知道与之相关的方法即可。
      • 少用继承多用组合(合成复用)

        • 定义:尽量使用对象组合,而不是继承来达到复用的目的
        • 理解:把继承而来的功能,重构为类内的成员
      • 最少知识原则(迪米特法则)

        • 定义:每一个软件单位对其他的单位都只有最少的知识,而且局限于那些与本单位密切相关的软件单位。
    • 模式:

      • 状态模式

        • 当一个对象的内在状态改变时,允许改变其行为,这个对象看起来像是改变了类
        • 主要解决的事当控制一个对象状态转换的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同的一系列类当中,可以吧复杂的逻辑判断简单化
      • 外观模式 Facade

        • 定义:通过引入一个外观角色来简化客户端与子系统之间的交互,为复杂的子系统调用提供一个统一的入口,降低子系统与客户端的耦合度,且客户端调用非常方便。
      • 单例模式 Singleton

        • 在单例类的内部实现只生成一个实例,同时它提供一个静态的工厂方法(?),让客户可以访问它的唯一实例;为了防止在外部对其实例化,将其构造函数设计为私有;

        • 主要缺点:

          • 单例模式没有抽象层,单例类的扩展有很大的困难
          • 单例类职责过重,在一定程度上违背了“单一职责原则”
          • 滥用可能导致:如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。
        • 适用场景:

          • 系统只需要一个实例对象,如系统要求提供一个唯一的序列号生成器或资源管理器,或者需要考虑资源消耗太大而只允许创建一个对象。
          • 客户调用类的单个实例只允许使用一个公共访问点,除了该公共访问点,不能通过其他途径访问该实例。
      • 中介者模式

        • 类比:在一群同学中创建一个QQ群,让所有人能在里面聊天
        • 专门创建一个类,用来负责其他各个模块之间的信息传递和调用
      • 桥接模式 Bridge

        • 将抽象部分与它的实现部分分离,使他们都可以独立地变化

        • 用意:将抽象化与实现化脱耦,使得两者可以独立地变化

          • 抽象化:存在于多个实体中的共同的概念性联系,就是抽象化。作为一个过程,抽象化就是忽略一些信息,从而把不通用的实体当做同样的实体对待
          • 实现化:抽象化给出的具体实现,就是实现化
          • 脱耦:所谓耦合,即两个实体行为的某种强关联,而将它们的强关联去掉,就是耦合的解脱,称为脱耦。在这里指将抽象化和实现化之间的耦合解脱开,或者说将它们之间的强关联改换成弱关联。
      • 策略模式

        • 定义:定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。
        • 就是为不同的处理方式单独创一个类,并且这些类都继承自同一个策略接口
      • 模板方法模式

        • 定义一个操作中算法的框架,而将一些步骤延迟到子类中。模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
        • 这里的模板不是C#里的模板,是字面意思的。
        • 把一个流程抽象出来,比如进餐厅->吃东西->买单。然后这个模板方法类的子类就可以重写其中的三个方法,或是只保留部分方法。
      • 状态模式(有限状态机FSM)

        • 状态机拥有者、Transition、stateID、

        • FSMState类:

          • 字典<transition,stateID>用来存储转换到其他状态的条件
          • PerformTransition的时候做上个状态的离开方法和下个状态的进入方法
        • 符合单一职责原则,每个状态负责独立的逻辑

      • 工厂模式 Factory

        • 旨在通过一个工厂来创建对象,将对象的创建过程封装起来,客户端代码无需直接调用构造函数

        • 简单工厂

          • 把创建方法细节放到工厂类里,只需要传入必要的参数
          • 但不符合开闭原则,每次增加一个要生产的物件,都需要去修改工厂类里的创建业务逻辑。
          • 人话:定义一个工厂类,来专门负责生产某些需要频繁实例化的物件,并封装成一个Create方法,供客户端或外部调用。这个方法可静态可不静态。
        • 工厂方法

          • 去掉了简单工厂模式中工厂方法的静态属性,使得它可以被子类继承。这样在简单工厂模式里集中在工厂方法上的压力可以由工厂方法模式里不同的工厂子厂来分担。
          • 人话:每个物件单独匹配一个工厂,将所有的工厂抽象出一个工厂父类,在父类中统一提供生成创建物件的方法,并由子工厂去重写。
        • 抽象工厂

          • 工厂方法pro max。
          • 例:在某个汽车型号之内,还有各个零部件的各自的型号。这就意味着,生产该型号汽车的工厂,还需要知道去哪些零部件工厂拿零件。
          • 人话:工厂套娃
        • 总结:无论简单工厂、工厂方法、抽象工厂,都属于工厂模式,在形式特点上也极为相似,最终目的都是为了解耦。使用时,不必理会是用的哪个,它们之间的演变往往令人捉摸不透。只需关心降低耦合度的目的是否达到。

        • 实际应用:使用泛型来选择生产哪个对象

      • 建造者模式 Builder

        • 主要思想是将一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
        • 旨在解决复杂对象的创建问题,特别是当对象的构造过程非常复杂、需要一步步构建,并且具有多个可选参数或配置选项时。
        • builder定义好各部分实现方法之后,由director进行指挥动工
      • 享元模式 Flyweight

        • 定义:采用一个共享来避免大量拥有相同内容对象的开销。这种开销中最常见、直观的就是内存的损耗。享元模式以共享的方式高效地支持大量的细粒度对象。
        • 人话:你的就是我的,我的就是你的。
        • 即有同样属性和字段的类生成的对象,共享一个内存或者说Model,就不再是每个对象单独存储其属性,转而全都放在一起,
      • 组合模式

        • 定义:将对象组合成树形结构,以表示“部分整体”的层次结构。组合模式使得用户对单个对象和使用具有一致性。
        • Component下可以是leaf叶子结点也可以是继承自Component的Composite
      • 命令模式 Command

        • 单独创一个类去执行,让这个命令对象自动GC吗?
      • 责任链模式 Chain of Responsibility

        • 是对象的行为模式。其使多个对象都有机会处理请求,从而避免请求的发送者和接受者直接的耦合关系。
        • 将这些对象连成一条链,沿着这条链传递该请求,直到有一个对象处理它为止。
        • 责任链模式强调每一个对象及其对下家的引用来组成一条链,利用这种方式将发送者和接受者解耦。
      • 观察者模式 Observer

        • 就是事件系统
        • 是一种行为型设计模式,定义了一种一对多的依赖关系。在这种模式中,一个目标对象管理所有依赖于它的观察者对象,并且在它本身的状态发送改变时主动发出通知。这通常通过调用个观察者所提供的方法来实现。
      • 备忘录模式 Memento

        • 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可将该对象恢复到原先保存的状态。
        • 把数据保存的功能,单独开一个类来负责
        • Originator、Memento、Caretaker
      • 访问者模式

        • 用一个Container来管理,
      • 适配器模式

        • 概述:将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以在一起工作
        • 实现:通过适配器类去持有和调用该插件,适配器类是继承自目标类的。
        • 应用:上线后新加的需求,比如敌人变伙伴
      • 代理模式

        • 类比:VPN
        • 结构型设计模式,通过提供一个代理对象来控制对另一个对象的访问。这种模式可以在不改变原始对象的前提下,为其添加额外的功能或者在访问时进行某些处理。
      • 装饰模式

        • 定义:装饰模式动态地将责任附加到对象上,若要扩展功能,装饰模式提供了比继承更有弹性的替代方案。
        • 套娃
      • 迭代器模式

        • 定义:提供一种方法访问一个容器对象中的各个元素,而又不暴露该对象的内部细节。属于行为类模式
      • 原型模式

        • 把声明的父类强转成子类来用
      • 解释器模式

        • 行为类设计模式,它用于对一种语言的句子进行解释和执行。
        • 适用于某些重复出现的问题可以用一种简单的语言来进行表达的场景,例如:编译器、运算表达式

  • 实现过程中产生的疑惑:

    • 状态模式与状态机的区别?
    • IOC容器是不是就是起到外观类的作用?
    • 单例模式的懒汉式和饿汉式具体含义?
    • 那IOC容器和中介者模式又有没有关系?
    • 导航组件NavMeshAgent?
    • 桥接模式为什么叫桥接?
    • 重构的意义与作用
    • 建造者模式和工厂模式有什么区别?
    • 这么多的设计模式,在实际的项目开发中都必须用上吗?
    • PlayerPrefabs类?
    • 那这个访问者模式总该跟IOC容器有关系了把?

  • 对疑惑的解答:

    • 状态模式是一种程序设计模式,而有限状态机FSM是一个数学模型,一种抽象机器(“行为树”也是一个数学模型,一种抽象树)

      状态机是为了解决某些问题而提出的数学模型,并非编程领域特有。其描述了在任何给定时间都处于某一个状态的计算机,它可以响应某些输入、触发、事件而从一种状态更改为另一种状态,关注点是状态及其切换。

      实际上就是以状态模式的思路来实现状态机,可以认为状态机试“运动中的状态模式”

    • IOC与外观模式相似,但也有所差距。因为事实上,在实际项目之中,客户端也不是直接调用IOC去获取,或者说有这个权力去找到IOC容器的。我们是通过接口赋予权力,并为该接口写扩展方法去调用。即把这个过程封装起来了。

      而外观模式就是简单的抽象出来一个管理类,去统一管理调用底层模块,并把接口暴露给客户端。

    • 单例模式两种模式

      • 饿汉式

        • 在程序启动或单例模式类被加载的时候,单例模式实例就已经被创建
        • 饿汉式是立即加载的方式,无论是否会用到这个对象,都会加载。
        • 如果在构造方法里写了性能消耗较大,占时较久的代码(如建立与数据库的连接),那么启动时可能会感觉稍微有些卡顿。
        • 无需关注多线程问题,简单明了,适用于实例在系统中经常被用到的情况
      • 懒汉式

        • 当程序第一次访问单例模式实例时才进行创建
        • 懒汉式是延迟加载的方式,只有使用的时候才会加载
        • 懒汉式需要考虑线程安全性,因为在多线程环境下,需要保证只有一个实例被创建
        • 懒汉式在启动时感觉比饿汉式略快,因为并没有做对象的实例化。但在第一次调用时会进行实例化操作,感觉上略慢。
      • 故而根据业务需求,如果有充分的启动和初始化时间,可以选择饿汉式,否则建议懒汉式。

    • IOC与中介者模式区别

      • IOC作用:通过IOC,应用程序只需定义好对象的依赖关系和配置信息,容器会根据这些信息来创建对象,并自动注入对象之间的依赖关系。
      • 中介者模式作用:用于降低多个对象和类之间的通信复杂性,提供了一中松耦合的方式来管理对象之间的交互。
    • 导航组件NavMeshAgent

      • 作用:负责控制游戏对象的导航行为。它使用场景中的导航网格(NabMesh)来寻找到达目标位置的最佳路径,并自动处理避免障碍物。
      • 是实现自动寻路和避障的关键组件,适用于各种游戏对象。
    • 桥接模式的桥接

      • 桥接字面意思:用桥去连接。即通过一座桥把两个地点连接起来,使它们可以相互来往

      • 核心:通过组合而不是继承,来连接抽象和实现的部分

        • 继承:

          • 子类可以重用父类的代码,也继承父类所有特性,包括不一定需要的部分
          • 会导致类之间的紧耦合,一旦父类发生变化,子类也可能受到影响
        • 组合

          • 将不同类的对象和功能组合到一个更大的类中,以创建新功能
          • 允许我们选择性地将不同的功能组合在一起,而不会继承不需要的部分
    • 代码重构:

      • 定义:一种用于改进现有代码库设计的受控技术。

      • 目的:

        • 提高代码质量:消除重复代码和遵循最佳实践
        • 保持系统健壮:避免破坏系统的同时改进代码,降低引入错误的风险
        • 提高代码理解度:使代码更易于阅读理解,帮助找到潜在bug
        • 加速开发速度:良好设计是快速开发的基础,使代码更易于修改和增加新功能
    • 建造者模式和工厂模式的联系和区别

      • 联系:都是面向对象设计中的创建型模式

      • 区别:解决的问题和应用场景有所不同

        • 目的不同:建造者关于于复杂对象的构建过程,工厂关注于把创建封装起来
        • 复杂性:建造者用于复杂对象,工厂简单复杂对象都可以
    • 选择设计模式的指导原则:

      • 根据需求:

        • 小而简单的项目,可能只需要一些基本的设计模式,例如工厂模式和单例模式
        • 复杂的系统,可以考虑用更多设计模式来提高代码可维护性和可扩展性
      • 遵循最佳实践:

        • 在适用场景中充分发挥某个设计模式的优点
      • 团队共识:

        • 在团队中尽可能达成共识,使代码保持一致
    • PlayerPrefabs类

      • 用于数据本地持久化保存与读取的类,允许开发人员在玩家的设备上存储少量的数据,以便在应用程序的生命周期内或多次启动应用程序之间持久存在。

      • 可以存储和读取int、float、string类型的数据

      • 存储位置:

        • Mac OS X 平台下,数据存储在 ~/Library/Preferences​ 文件夹中,文件名为 unity.[company name].[product name].plist​。
        • Windows 平台下,数据存储在注册表的 HKEY_CURRENT_USER\Software [company name] [product name]​ 键下。
      • 在实际开发中,需要考虑其他方案如数据库,以满足更复杂的数据管理需求。

    • IOC容器和访问者模式

      • 不好意思,还是没关系

日期:

posted @   静候霜白  阅读(19)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示