作业二:软件设计原则、设计模式

这个作业属于哪个课程 班级的链接
这个作业要求在哪里 作业要求的链接
这个作业的目标 系统地了解和学习软件设计的相关原则

相关书籍/网站

一、设计原则

  在软件开发中,为了提高软件系统的可维护性和可复用性,增加软件的可扩展性和灵活性,程序员要尽量根据7条原则来开发程序,从而提高软件开发效率、节约软件开发成本和维护成本。

设计原则 定义 优点
开闭原则 一个软件实体应当对扩展开放,对修改关闭 提高软件系统的可复用性以及维护性
里氏替换原则 子类型必须能够替换它们的基类型。反过来的代换不成立
  • 约束继承泛滥
  • 加强程序的健壮性,同时变更时也可以做到非常好的兼容性
  • 提高程序的维护性、扩展性
  • 降低需求变更时引入的风险
  • 依赖倒置原则
  • 高层模块不应该依赖低层模块,二者都应该依赖其抽象
  • 抽象不应该依赖细节,细节应该依赖抽象
  • 减少类间的耦合性
  • 提高系统稳定性
  • 提高代码可读性和可维护性
  • 减少并行开发引起的风险
  • 单一职责原则
  • 不要存在多于一个导致类变更的原因
  • 一个类/接口/方法只负责一项职责
  • 降低类的复杂度
  • 提高类的可读性
  • 提高系统的可维护性
  • 降低变更引起的风险
  • 接口隔离原则
  • 用多个专门的接口,而不使用单一的总接口,客户端不应该依赖它不需要的接口
  • 一个类对一个类的依赖应该建立在最小的接口上
  • 建立单一接口,不要建立庞大臃肿的接口
  • 尽量细化接口,接口中的方法尽量少
  • 注意适度原则,一定要适度
  • 可以预防外来变更的扩散,提高系统的灵活性和可维护性
  • 提高了系统的内聚性,减少了对外交互,降低了系统的耦合性
  • 保证系统的稳定性
  • 减少项目工程中的代码冗余
  • 迪米特原则 一个对象应该对其他对象保持最少的了解,使得系统功能模块相对独立,这样当一个模块修改时,影响的模块就会越少,扩展起来更加容易。
  • 降低了类之间的耦合度,提高了模块的相对独立性
  • 提高了类的可复用率和系统的扩展性
  • 合成复用原则 尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现 可以使系统更加灵活,降低类与类之间的藕合度一个类的变化对其他类造成的影响相对较少

    二、设计模式

      是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。它描述了在软件设计过程中的一些不断重复发生的问题,以及该问题的解决方案。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。

    创建型模式

    模式
    概念
    设计原则
    使用场合
    工厂方法模式 定义一个创建产品对象的工厂接口,让子类决定实例化哪一种实例对象,也就是将实际创建实例对象的工作推迟到子类当中,核心工厂类不再负责具体产品的创建 开闭原则
    依赖倒置原则
  • 当子类型可能会有很多,以后需要不断增添不同的子类实现时
  • 当一个系统尚在框架设计阶段,还不知道将来需要实例化哪些具体类时
  • 系统设计之初不需要具体对象的概念(或者说没有具体对象的概念)
  • 抽象工厂模式 提供一个接口,用于创建相关或者依赖对象的家族,而不需要指定具体的实现类 开闭原则
  • 创建产品家族,相关产品集合在一起使用的时候
  • 想要提供一个产品类库,并只想显示其接口而不是实现时
  • 通过组合的方式使用工厂时
  • 建造者模式 将复杂对象的创建与表示分离,使得同样的构建过程可以创建不同的表示 分步骤创建复杂对象
    构建和表示分离
    单一职责原则
  • 当生成的产品对象内部具有复杂的结构时
  • 当复杂对象需要与表示分离,可能需要创建不同的表示时
  • 当需要向客户隐藏产品内部结构的表现时
  • 原型模式 用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象 考虑产生对象的复杂度和类复用
    结合系统结构考虑使用浅复制还是深复制
  • 产生对象过程比较复杂,初始化需要许多资源时
  • 希望框架原型和产生对象分开时
  • 同一个对象可能会供其他调用者同时调用访问时
  • 单例模式 确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例 当在系统中某个特定的类对象实例只需要有一个的时候,可以使用单例设计模式。需要注意的是,只有真正有“单一实例”的需求时才可使用

    结构型模式

    模式
    概念
    设计原则
    使用场合
    适配器模式 把一个类的接口转换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作 使用对象组合,面向接口和抽象编程
    开闭原则
  • 软件系统结构需要升级或扩展,又不想影响原有系统的稳定运行的时候
  • 转换类之间的差别不是太大的时候
  • 想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类协同工作的时候
  • 桥接模式 使得软件系统能够轻松地沿着多个方向变化,而又不引入额外的复杂度。用意是“将抽象化与实现化脱耦,使得二者可以独立地变化” 使用聚合关联,不使用继承关联
    抽象化层次和实现化层次脱耦
  • 不希望在抽象类和它的实现部分之间有一个固定的绑定关系
  • 类的抽象及实现都应该可以通过生成子类的方法加以扩充
  • 对一个抽象的实现部分的修改应对客户不产生影响,即客户的代码不必重新编译
  • 组合模式 将对象组合成树形结构以表示“部分-整体”的层次结构 统一对待个别对象和组合对象
    面向抽象编程
  • 想表示对象的“部分-整体”层次结构的时候
  • 希望用户忽略组合对象与单个对象的不同,用户将统一使用组合结构中的所有对象的时候
  • 装饰者模式 在不改变原类文件和使用继承的情况下,动态地扩展一个对象的功能 装饰者和被装饰者完全隔离开来
    对扩展开放,对修改关闭
    面向抽象编程
    优先使用对象组合
  • 需要为某个现有的对象动态地增加一个新的功能或职责时
  • 当某个对象的职责经常发生变化或者经常需要动态地增加职责,避免为了适应这样的变化而增加继承子类扩展的方式时
  • 外观模式 为子系统中的一组接口提供一个统一的高层接口,使子系统更容易使用;通过一个外观接口读/写子系统中各接口的数据资源,而客户可以通过外观接口读取内部资源库,不与子系统产生交互 迪米特法则
    将系统中可能发生变化的部分独立出来,进行封装
  • 一个软件系统的复杂度比较高,需要一个更高级别的简单接口简化对子系统的操作时
  • 当使用端与实现类之间有太多的相依性,需要降低使用端与子系统或子系统间的耦合性,增加子系统的独立性时
  • 当子系统是相互依存的,需要层级化子系统,简化子系统之间的相依性的时候,可以使用外观模式
  • 享元模式 以共享的方式高效地支持大量的细粒度对象,通过复用内存中已存在的对象,降低系统创建对象实例的性能消耗 共享细粒度对象,降低内存空间
    有效地隔离系统中的变化部分和不变部分
  • 当系统中某个对象类型的实例较多的时候
  • 在系统设计中,对象实例进行分类后,发现真正有区别的分类很少的时候
  • 代理模式 两个对象参与处理同一请求,接收的请求由代理对象委托给真实对象处理,代理对象控制请求的访问 延迟加载,提高系统效率
    单一职责原则
  • 远程代理为一个对象在不同的地址空间提供局部代理
  • 虚拟代理中,若一个对象的创建非常耗时,可通过代理对象去调用
  • 保护代理控制对原始对象的访问
  • 智能指引取代了简单的指针,它在访问对象时执行一些附加操作
  • 行为型模式

    模式
    概念
    设计原则
    使用场合
    责任链模式 很多对象由每一个对象对其下家的引用而连接起来形成一条链。客户端应用请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求 开闭原则
    单一职责原则
  • 有多个对象处理同一个请求,具体由哪一个来处理还不确定,只有在运行时才能确定哪个对象处理的情况
  • 消息具有多个接收者,而接收对象又是不明确的情况。只需要向其中的一个对象发出消息,由其内部具体处理
  • 同一个消息的多个处理对象可能会动态增加或者减少,需要动态地指定的情况
  • 命令模式 将一个请求封装为一个对象,从而使用户可用不同的请求对客户进行参数化;将请求排队或记录请求日志,支持可撤销的操作 开闭原则
    迪米特法则
  • 抽象出待执行的动作以参数化某对象
  • 在不同的时刻指定、排列和执行请求
  • 需要支持可撤销的操作
  • 需要支持修改日志功能
  • 需要支持事务系统
  • 解释器模式 给定一个语言的文法表示,并且定义一个解释器,用来解释语言中的句子 开闭原则
    将可能变化的部分封装在非终结符表达式中
  • 一种特定类型的问题发生的频率足够高,并且业务规则频繁变化,不断重复出现类似情况
  • 业务规则不是过于复杂烦琐,比较容易抽象出语法规则
  • 效率不是软件系统中主要考虑的因素
  • 迭代器模式 提供了一种模式顺序访问一个集合对象中的各个元素功能,而又不暴露其内部的表示 开闭原则
    单一职责原则
  • 访问一个集合对象的内容,而无须暴露它的内部表示
  • 支持对集合对象的多种遍历方式
  • 为遍历不同的集合对象结构提供一个统一的接口
  • 中介者模式 用一个中介对象来封装一系列对象之间的交互,使各个对象中不需要显式地引用其他对象实例,从而降低各个对象之间的耦合度,并且可以独立地改变对象间的交互关系 一对多的对象依赖转化为一对一依赖
    集中控制提高类的复用性
  • 一组对象以定义良好但是复杂的方式进行通信,产生的相互依赖关系结构混乱且难以理解(注意是多个对象之间相互依赖)
  • 想定制一个分布在多个类中的行为,而不想生成太多的子类的场合
  • 产品架构的研发,更需要易于扩展的场合
  • 备忘录模式 在不破坏封闭的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可将该对象恢复到原先保存的状态 封装边界的保持
    双重接口实现,保证安全性
  • 需要在某一时刻恢复一个对象先前的状态时
  • 需要在外部保存对象某一时刻的状态时,但如果用一个接口来让其他对象直接得到这些状态,将会暴露对象的实现细节并破坏对象的封装性
  • 观察者模式 又称为发布/订阅模式,定义了对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新 开闭原则
    单一职责原则
    依赖倒置原则
  • 当一个抽象模型有两个方面,其中一个方面依赖于另一个方面,需要将这两个方面分别封装到独立的对象中,彼此独立地改变和复用的时候
  • 当一个系统中一个对象的改变需要同时改变其他对象内容,但是又不知道待改变的对象到底有多少个的时候
  • 当一个对象的改变必须通知其他对象做出相应的变化,但是不能确定通知的对象是谁的时候
  • 状态模式 当一个对象的内在状态改变时允许改变其行为,这个对象看起来就像是改变了其类 开闭原则
    单一职责原则
  • 一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变其行为
  • 一个操作中含有庞大的多分支结构,并且这些分支决定于对象的状态
  • 策略模式 定义一系列的算法,将每一种算法封装起来并可以相互替换使用,让算法独立于使用它的客户应用而独立变化 开闭原则
    单一职责原则
  • 当多个类的表现行为不同,需要在运行时动态选择具体要执行的行为的时候
  • 需要在不同情况下使用不同的策略(算法),或者策略还可能在未来用其他方式实现的时候
  • 需要隐藏具体策略(算法)的实现细节,各个具体策略(算法)彼此独立的时候
  • 当一个类中出现了多种行为,而且在一个操作中使用多个条件分支来判断使用多种行为的时候
  • 模板方法模式 定义一个操作中的算法骨架,而将一些实现步骤延迟到子类当中,使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤 开闭原则
    好莱坞原则
  • 一次性实现一个算法不变的部分,并将可变的行为留给子类来实现
  • 各子类中具有公共行为的时候,应被提取出来并集中到一个公共父类中以避免代码重复
  • 当需要控制子类扩展的时候。模板方法在特定点调用钩子操作,这样就只允许在这些点进行扩展
  • 访问者模式 表示一个作用于某对象结构中的各元素的操作,它使用户可以在不改变各元素类的前提下定义作用于这些元素的新操作 开闭原则
    单一职责原则
  • 如果在一个对象结构中包含很多不同类型对象,它们有不同的接口,而想对这些不同对象实施一些依赖于其具体类的操作
  • 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而想避免让这些操作与这些对象的类关联起来
  • 当该对象结构被很多应用共享时,用访问者模式让每个应用仅包含需要用到的操作
  • 定义对象结构的类很少改变,但经常需要在此结构上定义新的操作
  • 三、心得体会

      刚开始接触软件编程的时候,我是把所有的代码都放在一个函数里面的。后来随着学习的深入,开始把代码分装,但由于没有规范地学习过软件设计原则和设计模式,我的代码分装不够合理,就拿我上学期做的数据库课设(代码被我删了,故无图)来说,虽然有意识地按照单例原则、单一职责原则、接口隔离原则来进行分包和封装,但有些地方还是做得不够好,而且当时也没有意识到使用软件设计模式来进行开发,故而这个课设在现在看来还是还是问题多多啊,以后的代码开发要好好地使用软件设计原则和设计模式。

    四、相关截图

    posted @   月明风清星流痕  阅读(134)  评论(0编辑  收藏  举报
    相关博文:
    阅读排行:
    · 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
    · 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
    · ollama系列1:轻松3步本地部署deepseek,普通电脑可用
    · 按钮权限的设计及实现
    · 【杂谈】分布式事务——高大上的无用知识?
    点击右上角即可分享
    微信分享提示