软件设计的七大原则

面向接口编程而非面向实现

  • 客户端通过一系列抽象操作实例,而无需关注具体类型。
  • 便于灵活切换一系列的功能,现实软件的并行开发

开放封闭原则OCP

  • 核心思想:对扩展开放,比修改关闭。增加新功能而不改变原有代码
    • 在软件系统开发过程中,软件的需求往往会随着时间的推移而发生变化。因此进行软件设计是需要怎样的设计才能面对需求的改变却可以相对保持稳定,从而使得系统在第一个版本以后不断推出新的版本,如果一个软件设计符合开闭原则,那么可以非常方便的对系统进行扩展,而且在扩展时无须修改现有代码,使得软件系统在拥有适应性和灵活性的同时具备较好的稳定性和延续性。
    • 为了满足开闭原则,需要对系统进行抽象化设计,抽象化是开闭原则的关键。在进行软件设计时,一般先评估出最有可能发生变化的类,然后构造抽象来隔离那些变化。当变化发生时,无须对抽象层进行任何改动,只需要增加新的具体类来实现新的业务功能即可,实现在不修改已有代码的基础上扩展系统的功能,达到开闭原则的要求

单一职责原则SRP

  • 核心思想:一个类有且只有一个改变它的原因。适用于基础类,不适用基于基础类构建复杂的聚合类。
    • 一个类不要负责太多杂乱的工作。在软件系统中,如果一个承担的责任过多,就等于把这些责任耦合在一起,一个职责的变化可能会削弱或抑制这个类完成其他职责的能力。这种耦合会导致脆弱的设计,当变化发生时设计会遭受到意想不到的破坏。
    • 以项目开发为例,如果项目组成员每个人的职责都很明确,可以专心开发自己负责的模块,则项目成果的质量往往很高。相反,如果职责不清晰,分工就会混乱,极有可能出现 A 负责N个模块,而 B 则可以在一旁摸鱼,如果 A 负责的模块中有多个模块集中暴露问题时,A就很高质量的将问题从容解决。
    • 自己负责领域的事情都做,不是自己领域的事情不去插手。
    • 实现高内聚,低耦合的指导方针,它是最简单但有最难运用的原则。需要设计人员发现类的不同职责并将其分离,而发现类的多重职责需要设计人员具有较强的分析设计能力和相关实践经验。

依赖倒置原则DIP

  • 核心思想:客户端代码调用的类尽量依赖使用抽象的组件,抽象是稳定的,实现是多变的。
    • 依赖倒置原则要求我们在程序代码中传递参数时或在关联关系中,尽量引用层次高的抽象类。
    • 使用接口和抽象类进行变量类型声明,参数类型声明,方法返回类型声明,以及数据类的转换等,而不要用具体的类来做这些事情
    • 为了确保该原则的应用,一个具体的类当只实现接口或抽象类中声明过的方法,而不要给出多余的方法,否则将无法调用到在子类中增加的新方法。
    • 在引用抽象层后,系统在具有很好的灵活性,在程序中尽量使用抽象层进行编程,而将具体类写在配置文件中,这样一来,如果系统行为发生变化,只需要对抽象层进行扩展,并修改配置文件,而无须修改原有系统的源代码,在不修改的情况下来扩展系统的功能,满足开闭原则的要求
    • 我们需要针对抽象层编程,而将具体类的对象通过依赖注入的方式注入到其他对象中,依赖注入是指当一个对象要与其他对象发生依赖关系时,通过抽象来注入所依赖的对象。这些方法在定义时使用的是抽象类型,在运行时再传入具体的类型对象,由子类对象来覆盖父类对象

组合复用原则CRP

  • 核心思想:如果仅仅是为了代码复用优先选择组合复用,而非继承复用。组合的耦合性相对继承低。尽量使用对象组合,而不是继承来达到复用的目的
    • 在一个新的对象里通过关联关系包括组合关系和聚合关系来使用一些已有的对象,使之成为新对象的一部分,新对象通过委派调用已有对象的方法达到复用功能的目的
    • 首先应该考虑使用组合|聚合,组合|聚合可以是系统更加灵活,降低类与类之间的耦合度,一个类的变化对其他类造成的影响相对较少
    • 其次才考虑继承,在使用继承时,需要严格遵循里氏替换原则,有效使用继承会有助于对问题的理解,降低复杂度,而滥用继承反而会增加系统构建和纬度的难度以及系统的复杂度,因此需要慎重使用继承复用
    • 通过继承来复用的主要问题在于继承复用会破坏系统的稳定性,因为继承会将基类的实现细节暴露给子类,由于基类的内部细节通常对于子类来说是可见的,所有这种复用又称白箱复用,如果基类发生改变,那么子类的实现也不得不发生改变,从基类基础而来的实现是静态的,不可能在运行时发生改变,没有足够的灵活性,而且继承只能在有限的环境中使用(如类没有声明为不能被继承)。
    • 由于组合||聚合关系可以将已有的对象(也可称为成员对象)纳入到新对象中,使之成为新对象的一部分,因此新对象可以调用已有对象的功能,这样做可以使得成员对象的内部实现细节对于新对象不可见,所有这种复用又称为黑箱复用,相对继承关系而言,其耦合度相对较低,成员对象的变化对新对象的影响不大,可以在新对象中根据实际需要有选的调用成员对象的操作,合成符合可以在运用时动态进行,新对象可以动态的引用于成员对象类型相同的其他对象。

里氏替换原则LSP

  • 核心思想:父类出现的地方可以被子类替换,在替换后依然把持原功能。子类要拥有父类的所有功能,子类重写父类方法时,尽量选择扩展重写,防止改变了功能。
    • 子类的所有方法都必须在父类中声明,或子类必须实现父类中声明的所有方法。为了保证系统的扩展性,在程序中通常使用父类来进行定义,如果一个方法只存在子类中,在父类这不提供响应的声明,则无法以父类定义的对象中使用该方法。
    • 尽量把父类的设计为抽象类或者接口,让子类继承父类或者实现接口,并实现父类中声明的方法,运行时,子类实例替换父类实例,从而很方便的扩展系统的功能,同时无须修修改原有子类的代码,增加新的功能可以通过增加一个新的子类来实现。是开闭原则的具体实现手段之一。

接口隔离原则ISP

  • 核心思想:尽量定义小而精的接口interface,少定义大而全的接口。本质和单一职责相同,接口之间功能隔离,实现类需要多个功能可以进行选择多实现或者接口之间做继承。
    • 使用多个专门的接口时,而不是使用单一的总接口,即客户端不应该依赖那些它不需要的接口
    • 当一个接口太大时,我们需要将它分割成一些更细小的接口,使用该接口的客户端仅需要知道与之相关的方法即可。
    • 每一个接口应该承担一种相对应的角色,不干不该干的事儿,该干的事儿都要干,是接口的职责明确。
    • 在面向对象编程语言中,实现了一个接口就需要实现该接口中定义的所有方法,因此如果接口方法过多,其实现类中就不得不去处理许多自己根本不需要的方法,故大的总接口使用起来不一定很方便,为了使接口的职责单一,需要将大的借口根据其职责不同分别放在不同的小接口中,以确保每个接口使用起来都较为方便,并都承担某一单一角色。

迪米特法则LOD

  • 类与类交互时,在满足功要求的基础上,传递的数据越少越好。因为这样可以降低耦合度。

    • 一个实体应当尽量的少于其他实体之间发生相互作用,使得功能模块相对独立
    • 通过引用一个合理的第三者来降低现有对象之间的耦合度
    • 在设计系统时,应该尽量的减少对象之间的交互,如果两个对象之间不必彼此直接交互,那么这两个对象就不应当发生任何直接的交互,如果其中的一个对象需要调用另一个对象的某一个方法时,可以通过第三者转发这个调用。
      • 在类的划分上,应当尽量的创建松耦合的类,类之间的耦合度越低,就越有利于复用,一个处于在松耦合中的类一旦被修改,不会对关联的类造成太大的波及,
      • 在类的结构设计上,每一个类都当尽量降低其成员变量和成员函数的访问权限;在类的设计上只要有可能,一个类应当设计成不变类。
      • 在对其他类的引用上,一个对象对其他对象的引用应当降到最低。
posted @   unknown-n2  阅读(195)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
点击右上角即可分享
微信分享提示

目录导航