设计模式是针对软件开发过程中遇到的一些设计问题,总结出来的一套解决方案或者设计思路。
https://zh.wikipedia.org/wiki/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F_(%E8%AE%A1%E7%AE%97%E6%9C%BA)
面向对象编程是一种编程方式或者编程风格, 以类或者对象作为组织代码的基本单元。包含封装,多态,继承,抽象等4个基本特性。
面向对象语言是支持类和对象的语法机制,并有现在的语法机制,能够方便的实现面向对象的4大特征(封装、抽象、继承、多态)的编程语言。封装特性存在的意义,一方面是保护数据不被随意修改,提高代码的可维护性;另一方面是仅暴露有限的必要接口,提高类的易用性。
封装也叫做数据隐藏和数据访问保护,通过暴露有限的访问接口,授权外部仅能通过类提供的方式来访问内部信息和数据。它需要编程语言提供权限访问控制语法来支持, 比如 Java 中的 private 、protected 、public等关键字。
封装说的是如何隐藏信息和保护数据,抽象说的是如何隐藏方法的具体实现,抽象可以通过接口或者抽象类来实现,但也并不需要特定的语法来支持。抽象存在的意义,一方面是提高代码的可扩展性和维护性, 修改方法时不需要改变定义,减少代码的改动范围,另外一方面也是处理复杂问题的有效手段, 能够有效过滤掉不需要关注的信息。
继承用来表示 类之间 is-a 的关系,分为两种模式, 单继承和多继承,单继承表示一个子类只能继承一个父类,多继承表示一个子类可以继承多个父类,为了实现继承这个特性,编程语言需要提供特殊的语法机制来支持。继承主要是用来解决代码复用的问题。
子类可以替代父类,实际代码运行过程中,调用子类的方法实现。多态这个特性需要编程语言的特殊语法机制来实现,比如继承、接口类,duck-typing, 多态可以提高代码的扩展性和复用性,有很多设计模式,设计原则,编程技巧的代码实现基础。
类的继承层次如果很深,继承的关系会越来越复杂,而且层次很深很复杂的继承关系,会导致代码可读性变差,子类的实现依赖父类的实现,两者高度耦和,一旦父类代码修改,会影响子类的逻辑。
Go 围绕 struct ,提供了私有属性、method、interface、struct 嵌套能力,可以用更轻量的方式实现面向对象(封装,继承,多态,抽象)
基于接口编程而非实现编程
接口是一组协议或者约定,是功能提供者提供给使用者的一个功能列表,接口在不同的场景下有不同的解读,
好的代码设计,不仅能够应对当下需求,而且在将来需求发生变化的时候,仍然可以在不破坏原有代码设计的情况下灵活应对。
在这里插入图片描述
一个类或者一个模块只负责完成一个职责或者功能,不要设计大而全的类, 要设计粒度小,功能单一的类, 单一职责是为了实现代码高内聚,低耦合,提高代码的复用性,可读性,可维护性。
不同应用的场景,不同阶段的需求背景,不同的业务层面,对通一个类的职责是否单一,可能会有不同的判定结果。
如果出现以下情况,表示不满足单一职责原则:
添加一个新功能,应该是通过现有共扩展代码(新增模块,类,方法,属性等), 而非修改已有代码的方式来完成。
我们对一个类添加新的方法。添加方法相当于修改类,在类这个层面,这个代码改动可以被认定为“修改”;但这个代码改动并没有修改已有的属性和方法,在方法(及其属性)这一层面,它又可以被认定为“扩展”
时刻具备扩展意识,抽象意识,封装意识。编码时,要多花时间去思考,代码未来可能哪些需求变更,如何设计代码结构,事先留好扩展点,以便在未来在需求变更时,在不调整代码结构的基础上,做到最小代码的修改,将新代码灵活的放到扩展点上。
最常用的提高代码扩展的方法有:多态,依赖注入, 基于接口而非实现编程,与大部分设计模式。
里式替换原则的英文翻译是:Liskov Substitution Principle,缩写为 LSP。这个原则最早是在 1986 年由 Barbara Liskov 提出,他是这么描述这条原则的:If S is a subtype of T, then objects of type T may be replaced with objects of type S, without breaking the program。
子类对象能给替换程序中父类出现的任何对方,并且保证程序的行为逻辑及正确性不被破坏。
多态是面向对象编程等一大特性,也是面向对象编程语言的一种语法,它是一种代码实现的思路,里式转换原则设计中,是用来指导继承关系中子类如何设计,子类的设计保证在替换父类时,不改变原有逻辑和程序的正确性。
接口隔离原则的英文翻译是“ Interface Segregation Principle”,缩写为 ISP。Robert Martin 在 SOLID 原则中是这样定义它的:“Clients should not be forced to depend upon interfaces that they do not use。”直译成中文的话就是:客户端不应该被强迫依赖它不需要的接口。其中的“客户端”,可以理解为接口的调用者或者使用者。
理解接口隔离重要是理解其中接口两字。接口理解一组接口集合,可以是某个服务的接口,可以是某个类的接口,如果部分接口被有这使用。
单一职责是针对的是类,模块,接口的设计,接口隔离原则相对单一原则更侧重于接口的设计。另外思考角度也不一样。接口隔离原则提供了一种判断接口是否单一的标准:通过调用者如何使用接口来判断,如果调用者使用部分接口或接口的部分功能,那接口的设计就不够单一
实际上,控制反转是一个比较笼统的设计思想,并不是一种具体的实现方法,一般用来指导框架层面的设计。这里所说的“控制”指的是对程序执行流程的控制,而“反转”指的是在没有使用框架之前,程序员自己控制整个程序的执行。在使用框架之后,整个程序的执行流程通过框架来控制。流程的控制权从程序员“反转”给了框架。
依赖注入和控制反转恰恰相反,它是一种具体的编码技巧。我们不通过 new 的方式在类内部创建依赖类的对象,而是将依赖的类对象在外部创建好之后,通过构造函数、函数参数等方式传递(或注入)给类来使用。依赖注入也是实现组合最简单的方式
type A struct {}
func NewA() A {
return A{}
}
type B struct {
a A
}
func NewB(a A) B {
return B{a:a}
}
func main() {
a := NewA()
// 依赖注入
b := NewB(a)
}
依赖反转原则也叫作依赖倒置原则。这条原则跟控制反转有点类似,主要用来指导框架层面的设计。高层模块不依赖低层模块,它们共同依赖同一个抽象。抽象不要依赖具体实现细节,具体实现细节依赖抽象。
其实主要含义是尽量保持简单
DRY 原则(Don’t Repeat Yourself)几乎人尽皆知。你可能会觉得,这条原则非常简单、非常容易应用。只要两段代码长得一样,那就是违反 DRY 原则了。真的是这样吗?答案是否定的。这是很多人对这条原则存在的误解。实际上,重复的代码不一定违反 DRY 原则,而且有些看似不重复的代码也有可能违反 DRY 原则。
通常存在三种典型的代码重复情况,它们分别是:实现逻辑重复、功能语义重复和代码执行重复。
迪米特法则的英文翻译是:Law of Demeter,缩写是 LOD。单从这个名字上来看,我们完全猜不出这个原则讲的是什么。不过,它还有另外一个更加达意的名字,叫作最小知识原则,英文翻译为:The Least Knowledge Principle。
迪米特法则法则强调不该有直接依赖关系的类之间,不要有依赖;有依赖关系的类之间,尽量只依赖必要的接口。迪米特法则是希望减少类之间的耦合,让类越独立越好。每个类都应该少了解系统的其他部分。一旦发生变化,需要了解这一变化的类就会比较少。
“单一职责原则”、“接口隔离原则”以及“最小知识原则”,都是实现高内聚低耦合的有效指导思想。“最小知识原则”更强调类与类之间的关系。
微信号:程序员开发者社区
博客:CSDN 王小明
关注我们,了解更多
关注后:回复 “AI” 或者 “内推”, 有惊喜