大家好,我是追麾(hui)。
上一次分析完Go的设计模式第一篇,有同学后台问一些设计原则的问题,这篇我们就来讲一下设计的一些原则,然后再继续设计模式的学习。下图是本文提纲。
关于程序设计有六大原则,具体原则如下,当然这个不是Go语言独有的,而是所有的语言都有的。了解了每个程序设计原则的目的,并且运用到我们的程序中去,会让我们的代码可读性高,更加优美,你也会更加爱上写代码。
定义:一个类或者一个模块只承担一个业务职责,一般地,一个类或者模块内部尽量做到高内聚,不同的类或者模块之间做到低耦合,这样的话代码质量就会很高。在Go语言里面一个struct就算一个对象,如果这个对象加上一些方法就能算一个类。
主要目的:单一职责的原则是让类或者模块的职责更加清晰明确,另外能降低程序复杂度,提高程序可读性和可维护性,也从一定程度下说可能可扩展性要好一些。
定义:一个(类、模块、函数等等)可以扩展,但是不可修改。在Go语言里面是没有办法直接通过继承重写的方式实现扩展,但是可以通过组合的方式来实现继承并扩展,后面我们会讲到组合模式会涉及到这个开放封闭原则。
主要目的:开放封闭原则主要是在软件需求发生变化时,目标类和模块的代码可以通过代码扩展实现新的需求,而不是修改已有的类或者模块,主要是防止在已有代码逻辑上修改制造代码缺陷。
定义:子类对象必须能够完全替换掉它们的父类对象,而不需要改变父类的任何属性。在Go里面可以通过接口的多重组合来实现继承和多态,但是实现起来是相对比较复杂的。
主要目的:里氏替换原则的核心目的主要是为了实现多态,通过继承的方式重写父类的方法,这样父类定义的对象引用可以通过不同的子类进行调用,然而同一个调用就能表现多态特征。
定义:高层模块不应依赖于低层模块,二者都应该依赖于抽象(抽象类和接口);抽象(抽象类和接口)不应依赖于细节,细节应依赖于抽象(抽象类和接口)。在Go语言中这个原则也是保留的,但是Go只有接口,是没有抽象类。
主要目的:依赖倒置原则主要是解耦的目的,减少类间的耦合性,能提高系统的稳定性,降低并行开发引起的风险,提高代码的可读性和可维护性。
定义:建立单一接口,不要建立臃肿庞大的接口。再通俗一点讲:接口尽量细化,同时接口中的方法尽量少。在Go语言中接口分离原则原则制定和其他语言没有差异,接口分离原则主要还是由开发者来决定的。
主要目的:接口分离原则主要是为了让接口尽量少,代码抽象度高,可复用性高。在根据接口隔离原则拆分接口时,是必须要满足单一职责原则。
定义:其实就是知道最少原则,也就是调用涉及的依赖尽可能的小。在Go语言中主要是通过大写方法名来实现让包外进行访问,这样在Go语言中实现迪米特原则也就比较方便了。
主要目的:迪米特原则是降低类间耦合,让类之间弱耦合,只有弱耦合了以后,类的复用率才可以提高,也可以说这个原则是让类之间达到解耦目的。
到这里我算是回答了后台咨询我的同学了,关于设计原则我只分享了定义以及每个设计原则的核心目的是什么,后面分享剩余的设计模式之后也会涉及到这些原则,并且运用到实际的模式中去。比如说第一篇的单例模式,其主要设计的原则是单一职责原则。第一篇工厂方法模式其主要设计的原则参照依赖倒置原则和开放封闭原则。
业界简单工厂模式定义:将目标产品创建行为分配给工厂类,由工厂类向客户端提供产品对象创建服务。
简单工厂模式优缺点
简单工厂模式的应用场景
简单工厂模式实现方式
像简单工厂模式其主要可以参照迪米特原则,让实现的方法或者类对外输出被创建与初始化。
我们的工作中经常会对接多个支付平台,然后需要去调用支付平台进行下单,每个支付平台就是不同的对象,我们通过一个NewPayPlatform创建对象,返回接口。这样就实现了简单工厂模式。下面我们通过业务中Go语言代码具体来讲解简单工厂模式。
package main
import "fmt"
func main() {
NewPayPlatform("test").CreatePayOrder()
}
// 支付平台的公共接口
type PayPlatformInterface interface {
//创建支付订单
CreatePayOrder()
}
type AliPay struct {
}
func (a *AliPay) CreatePayOrder() {
fmt.Println("CreatePayOrder 支付宝")
}
type WeiXinPay struct {
}
func (a *WeiXinPay) CreatePayOrder() {
fmt.Println("CreatePayOrder 微信支付")
}
// 简单工厂模式,AliPay 和 WeiXinPay是不同的对象, PayPlatformInterface 是接口
func NewPayPlatform(platform string) PayPlatformInterface {
switch platform {
case "alipay":
return &AliPay{}
case "weixin":
return &WeiXinPay{}
}
// 默认是调用支付宝
return &AliPay{}
}
看完Go的简单工厂模式,是不是发现和之前的工厂方法模式很像?工厂方法模式的调用可以不用组装公共方法,两种侧重点不一样的,工厂方法模式是侧重定义一批方法,简单工厂模式是侧重调用。
业界抽象工厂模式定义:为创建一组相关或者相互依赖的对象提供一个接口,而无需指定它们的具体类。抽象工厂模式可以说是是工厂方法模式的升级版,当需要创建的产品有多个产品线(产品族)时使用抽象工厂模式是比较好的选择。
抽象工厂模式优缺点
抽象工厂模式的应用场景:当需要创建的对象是一系列相互关联或相互依赖的产品族时,便可以使用抽象工厂模式,主要是让产品簇实现软件的可配置性。
抽象工厂模式实现方式
在Go的设计模式第一篇工厂方法模式里面我们讲了不同厂商的调用,把公共的方法封装成一批方法组,我们还是上一次的例子做一下升级来讲解一下抽象工厂模式。
我们在做聚合广告需要拉取facebook的数据,facebook当成一个工厂,facebook是auth 1.0授权是这个工厂方法,头条当成一个工厂,头条auth 2.0授权是这个工厂的方法。我们再建一个接口组合两个工厂的方法。下面我们具体看下Go的示例如何实现抽象工厂。
package main
import "fmt"
func main() {
a := AuthFactory{}
a.produceAuth1("fb").auth1()
}
type Auth1 interface {
auth1()
}
// facebook 用auth1授权
type FaceBookAuth struct {
}
func (f *FaceBookAuth) auth1() {
fmt.Println("facebook auth1")
}
type Auth2 interface {
auth2()
}
// toutiao 用auth2授权
type TouTiaoAuth struct {
}
func (t *TouTiaoAuth) auth2() {
fmt.Println("toutiao auth2")
}
// 抽象公共调用
type AbstractFactory interface {
produceAuth1(firm string) Auth1
produceAuth2(firm string) Auth2
}
type AuthFactory struct {
}
func (a *AuthFactory) produceAuth1(firm string) Auth1 {
switch firm {
case "fb":
return &FaceBookAuth{}
}
return nil
}
func (a *AuthFactory) produceAuth2(firm string) Auth2 {
switch firm {
case "toutiao":
return &TouTiaoAuth{}
}
return nil
}
分享完工厂模式(对工厂方法模式不了解的可以查看上一篇文章:【建议收藏】如何用Go写出优美的代码-Go的设计模式【单例模式,工厂方法模式】篇一),简单工厂模式,抽象工厂模式,我们这里做一下总结。