马SB Java高级互联网架构师VIP课程1-7班2022最新
如何编写sdk
一、背景引见
在平常工作中,我们会把通用的代码,兼并到一个通用的SDK中,增加大家工作效率,本文主要分享我们在编写SDK时分的准入规范以及相关编码思想。
首先需求答复,为什么要编写SDK?
1. 防止反复造轮子
2. 减少线上bug概率
1.1 防止反复造轮子
好的sdk能够协助团队省时省力,将相同的功用笼统到一个通用sdk中,前人栽树后人纳凉。
1.2 减少线上bug概率
1. 经过大家共同的优化出bug的可能性较低,即便出bug,也只需求修正sdk即可;
2. 若每个代码库都完成一遍,那每个代码库就都需求修复这个bug;
3. 每个同窗才能不同,写出代码的质量良莠不齐;
二、遵照的设计理念 SOLID
在程序设计的范畴内,SOLID是由Robert C.Martin提出的面相对象编程以及面向对象设计的五个根本准绳的缩写,这五个准绳分别是:
- 单一职责准绳(Single ResponsibilityPrinciple)
- 开闭准绳 (Open Close Principle)
- 里氏交换准绳 (Liskov Substitution Principle)
- 接口隔离准绳 (InterfaceSegregation Principle)
- 依赖反转准绳 (Dependence InversionPrinciple)
在编写SDK中,我们深信好的代码是设计出来的,而不是编写出来的这一理念,所以在设计之初我们就会依照这五大准绳,逐一考量我们能否的设计能否足够优秀,我们能否违犯了某项准绳。
接下来我们来逐一引见我们关于这五大准绳的了解:
2.1 单一职责准绳
定义
类的设计,尽量做到只要一个能够惹起它变化的缘由
了解
单一职责准绳的存在是为了保证对象的高内聚、保证同一对象的细粒度。在程序的设计上,假如我们采用了单一职责准绳,那么就要留意,开发代码过程中不要设计那些功用五花八门、包含很多很多不相关的功用的类,这样的类我们能够以为是违背单一职责准绳的。依照单一职责准绳设计的类中,应该有且只要一个改动要素;
举例子
package phone
// 只担任调整电话音量
type MobileSound interface {
// 音量+
AddSound() error
// 音量-
ReduceSound() error
}
// 只担任调整照片格式
type MobilePhoto interface{
// 亮度
Brightness() error
// 纵横比
AspectRatio() error
}
复制代码
这段代码是关于手机的两个类的结构,在设计的时分,我们将手机的音量控制和手机图片的调整类停止了辨别,在同一个类中不同功用的共同载体分别是音量控制和图片调整,这两个类中的功用是不产生依赖的,互相平行的关系,当手机的配置发作改动,那么这两个类中的功用都会产生一定的变化;
假如我们要对其中一个类停止调整,那么只需求在相应的interface中停止功用的优化即可,不会影响到其他功用的构造。
2.2 开闭准绳
定义:一个软件实体,应该对扩展开放,对修正关闭;
了解
针关于这个问题的产生是来自于关于代码停止维护的时分,假如对旧代码停止修正,那么可能会引入错误,这可能会招致我们对整个功用停止重新架构,并且重新测试;
为了避免这种状况的发作,我们能够采用开闭准绳,我们只对代码停止添加功用,扩展类中的功用,而不去修正原先的功用,这样能够避开由于修正老代码而产生的坑(深有领会);
举例子
// 只担任调整电话音量,同时具备一键最大和一键最小的功用
type MobileSound interface {
// 音量+
AddSound() error
// 音量-
ReduceSound() error
// 静音
Mute() error
// 一键最大
MaxSound() error
}
复制代码
还是这个手机的类,假如后期业务需求增加,请求我们参加静音和一键音量最大的功用,那么我们能够直接在这个音量控制接口中停止功用扩展,而不是去在音量加减的功用里停止修正,这样能够防止由于对内部逻辑的调整而产生的功用架构问题。
留意点
开闭准绳是一个十分虚的准绳,我们需求在提早预期好变化并做出规划,然后需求的变化总是远远超越我们的预期,遵照这个准绳我们应该把频繁变化的局部做出笼统,但却不能将每个局部都刻意的停止笼统;
假如我们无法预期变化,就不要去做刻意的笼统,我们应该回绝并不成熟的笼统。
2.3 里氏交换准绳
定义
一切援用基类的中央必需能透明的运用其子类的对象;
了解
子类对象交换父类对象的时分,程序自身的逻辑不能发作变化,同时不能对程序的功用形成影响;
举例
依然是用手机来举例子,我们定义的手机类中,参加了一个充电功用接口;
- 其中包含了无线充电和有线充电两个功用;
type Charge interface {
//有线充电
ChargeWithLine() error
//无线充电
ChargeWithoutLine() error
}
复制代码
- 但是我们并没有想到8848钛金手机这么一款高端商务上流手机并不具备无线充电的功用;
由于我们定义的父类并不能由子类完整交换,8848也是手机,但是由于它的功用并不完整具备手机类的功用,所以招致这个问题的产生,那么如何来处理这个问题呢?
我们能够将手机类的充电功用停止拆分,在父类中,我们只定义充电功用,那么我们就能够在8848子类里面设计详细的充电方式,来完善这个功用的接口。我们在手机类中仅定义了最根底的办法集,经过子接口SpecialPhone添加ChargeWithLine办法;
type MobilPhone interface {
Name() string
Size() int
}
type NormalCharge interface {
MobilPhone
ChargeWithLine() error
ChargeWithoutLine() error
}
type SpecialCharge interface {
MobilPhone
ChargeWithLine() error
}
复制代码
- 我们再经过SpecialPhone来提供对MobilPhone的根本完成:
type SpecialPhone struct {
name string
size int
}
func NewSpecialPhone(name string, size int) *SpecialPhone {
return &SpecialPhone{
name,
size,
}
}
func (mobile *SpecialPhone) Name() string {
return mobile.name
}
func (mobile *SpecialPhone) Size() int {
return mobile.size
}
复制代码
- 最后,Mobil8848经过聚合SpecialPhone完成MobilPhone接口, 经过提供ChargeWithLine办法完成Mobil8848子接口:
type Mobil8848 struct {
SpecialPhone
}
func NewMobil8848(name string, size int) MobilPhone {
return &Mobil8848{
*NewSpecialPhone(name, size),
}
}
func (mobile *Mobil8848) ChargeWithLine() error {
return nil
}
复制代码
留意点
在项目中,采用里氏交换准绳时,尽量防止子类的特殊性,采用该准绳的目的就是增加强健性,在版本晋级时也能有很好的兼容性,而一旦有了特殊性,那么代码间的耦合关系就会变得极端复杂;
2.4 接口隔离准绳
定义
- 客户端不应该依赖它不需求的接口;
- 类间的依赖关系应该树立在最小的接口上;
了解
- 客户端不能依赖于它所不需求运用的接口,这里的客户端我们能够了解为接口的调用方或者运用者;
- 尽量保证一个接口对应一个功用模块;
接口隔离准绳和单一责备准绳的区别是什么?
单一职责准绳主要是在业务逻辑层面上,保证一个类对应一个职责,注重的是关于模块的设计;
而接口隔离准绳则是主要针对接口的设计,对不同的模块提供不同的接口。
举例
比方下面这个例子,这段代码就是明晰的将接口依照不同的返回值停止了辨别,这样在调用的时分就能够防止由于不分明返回的认证信息状态而形成的逻辑上的错误。