Golang设计模式工厂模式实战写法示例详解

目录
  • 拆出主板
  • 工厂模式流程
  • 代码实战
    • 抽象能力,定义接口
    • 实现工厂,支持注册和获取实现
    • 主流程只依赖接口完成
    • 扩展 => 适配器,实现接口
    • 注册适配器到工厂里
  • 小结

拆出主板

今天带大家看一下怎么用 Go 写工厂模式的代码,我们来学习一个实战案例。这个写法笔者日常经常使用,能够很有效地帮助大家实现 Separation of Concerns。

主板就是一个程序的主流程。比如我们要基于一份学习资料来消化,吸收知识。我们可能有下面几步流程:

  • 准备好笔记本;
  • 打开资料;
  • 阅读资料内容,思考并记录关键点到笔记本上;
  • 做资料里包含的练习题;
  • 归纳总结,验证掌握程度。

这个资料,可以是纸质书籍,可以是电子书,可以是某个平台的专栏,形式有很多,但我们不 care,因为在主题流程中,只需要它是个资料,有资料的能力即可。

换句话说,我们把资料转换成一个 interface,定义如下:

type KnowledgeMaterial interface{
	GetContent() string
	GetExercises() []string
}

能给我们主体内容,能给我们练习题,满足这两点就够了。

所以,主板本质上是不 care 具体这个资料是什么的。

扩展则是基于 interface 的实现,或者类比一下 adapter,就是个适配器。我们可以定义出来 Book, Ebook, Column 各种各样的扩展,它们都实现了这个 KnowledgeMaterial 接口。

很多同学写代码的时候,拆不开主板,不知道自己的核心流程是什么,这一点是非常重要的。拆不出来【主流程】,就意味着你需要针对某个实体实现逻辑时,直接依赖了这个【实现】。

比如我们上面的 case,没有 KnowledgeMaterial 接口,你的流程变成了,翻开纸质书第一页,看看目录,然后翻到第一章,开始阅读书上的文字。。。。

这是很可怕的一件事,意味着一旦结构变了,你的代码是不可能适配的。你会需要各种 if else 来判断到底是哪种类型。如果后来又来了一种学习资料,叫做【视频课程】,这时候怎么办呢?

没有页供你翻了,你面对的实体变成了视频内容,想要适配,就势必不是容易的事。

所以,大家一定要练习这个能力,遇到问题,思考自己的主流程是什么,拆出主板,然后明确你对业务实体的诉求是什么,能否抽象化。

是一个实现了KnowledgeMaterial 接口的任意实体就 ok?还是必须得是 Book 这个具体的结构体才 ok?

如果你需要的只是个接口,能够抽象简化,就尽量用我们今天要说的工厂模式来做,这样你的主流程心智负担会小很多,此后新增扩展成本也很小。

工厂模式流程

  • 抽象出对实体的能力要求,变成接口;
  • 实现工厂,支持适配器注册,支持根据类型获取对应的接口实现;
  • 主流程只依赖接口完成;
  • 将你的扩展,变成 adapter 适配器,实现接口所要求的的能力;
  • 将你的适配器通过第二步里提到的方法,注册到工厂里。

这样的好处就在于,主板和扩展隔离,新增扩展的时候,只需要新增,不需要动主流程,不需要动其他扩展,避免了一大堆 if else 的写法。

代码实战

我们结合一开始提到的 KnowledgeMaterial 接口来简单示例一下。

抽象能力,定义接口

type KnowledgeMaterial interface{
	GetContent() string
	GetExercises() []string
}

实现工厂,支持注册和获取实现

新建一个 factory.go 文件,填充如下内容:

type KnowledgeAdapterFactory struct {
	sync.RWMutex
	adapters []KnowledgeAdapter
}
var (
	knowledgeAdapterFactory = KnowledgeAdapterFactory{
		adapters: []KnowledgeAdapter{},
	}
)
// RegisterKnowledgeAdapter 注册新的知识资料适配器
func RegisterKnowledgeAdapter(adapter KnowledgeAdapter) {
	knowledgeAdapterFactory.Lock()
	knowledgeAdapterFactory.adapters = append(knowledgeAdapterFactory.adapters, adapter)
        knowledgeAdapterFactory.Unlock()
}
// GetAllKnowledgeAdapters 获取所有知识资料适配器
func GetAllKnowledgeAdapters() []KnowledgeAdapter {
	return knowledgeAdapterFactory.adapters
}

主流程只依赖接口完成

重点关注和 adapter 相关的逻辑,其他部分省略:

func LearnKnowledge() {
	//准备好笔记本
	notes := openNotesForWrite()
	for _, adapter := range GetAllKnowledgeAdapters() {
		content := adapter.GetContent()
		// 阅读资料内容,思考并记录关键点到笔记本上
		writeNotes(content)
		// 做资料里包含的练习题
		for _, ex := range adapter.GetExercises() {
			doExecise(ex)
		}
	}
	// 归纳总结,验证掌握程度
	summary()
}

扩展 => 适配器,实现接口

新建一个包:book,用于实现纸质书籍的适配器。在其中新建 adapter.go 文件,填充如下代码

type Adapter struct {}
func (a *Adapter) GetContent() string {
	return "xxx"
}
func (a *Adapter) GetExercises() []string {
	return []string{"xxx"}
}

注册适配器到工厂里

这里写法其实相对灵活,很多人会选择直接在工厂定义的 factory.go 写注册逻辑,我个人不太喜欢这样。这就意味着每次新增适配器,都需要动工厂。

比较推荐直接在适配器的 init() 函数中完成注册,然后在 main 函数启动时 import 包进来,就执行了 init 函数。

这样写的好处在于当你新增一个扩展的时候,主流程和工厂都不需要动,只新增文件就好。

我们可以把上面的 adapter.go 新增一个函数即可:

type Adapter struct {}
func init() {
	RegisterKnowledgeAdapter(&Adapter{})
}
func (a *Adapter) GetContent() string {
	return "xxx"
}
func (a *Adapter) GetExercises() []string {
	return []string{"xxx"}
}

小结

工厂模式是一个很简单,容易上手的写法,重点还是在于大家要区分开主板和扩展,通过注册方式填充适配器,而不是通过 if else 来区分。希望今天介绍的写法对你有帮助,这里还可以有很多变形,本质是类似的。

以上就是Golang 工厂模式实战写法示例详解的详细内容,更多关于Golang 工厂模式的资料请关注我们其它相关文章!

(0)

相关推荐

  • Java设计模式之GOF23全面讲解

    一.什么是设计模式 设计模式(Design pattern) 是解决软件开发某些特定问题而提出的一些解决方案也可以理解成解决问题的一些思路.通过设计模式可以帮助我们增强代码的可重用性.可扩充性. 可维护性.灵活性好.我们使用设计模式最终的目的是实现代码的高内聚和低耦合. 二.设计模式的三大分类及关键点 1.创建型模式 对象实例化的模式,创建型模式用于解耦对象的实例化过程. 单例模式:某个类智能有一个实例,提供一个全局的访问点.工厂模式:一个工厂类根据传入的参量决定创建出哪一种产品类的实例.抽象工

  • Python Django框架设计模式详解

    目录 MVC设计模式 MTV设计模式 总结 MVC设计模式 MVC (Model-View-Controller) 是软件工程中常用的软件架构模式,它是一种分离业务逻辑与显示界面的设计方法.它把软件系统分为三个基本部分: M:业务模型(Model),代表一个储存数据的对象 V:视图(View),代表模型包含的数据的可视化 C:控制器(Controller),作用于模型于视图中,将数据流向模型对象,并在数据化时更新视图. MTV设计模式 Django中的MTV模式本质上和MVC是一样的,只是定义不

  • 详解用Go语言实现工厂模式(Golang经典编程案例)

    golang中的struct没有构造函数,一般可以使用工厂模式来解决这个问题.这个模式本身很简单而且使用在业务较简单的情况下.一般用于小项目或者具体产品很少扩展的情况(这样工厂类才不用经常更改). 代码结构如下:分别有main.go和student.go两个文件. 在student.go中: package model //定义一个结构体 type student struct{ Name string score float64 } //因为student结构体首字母是小写,因此是只能在mod

  • Go语言设计模式之实现观察者模式解决代码臃肿

    目录 引言 观察者模式 概念 我的理解 Go 实现观察者模式 Go 实现事件总线 代码 单测 总结 引言 我们先来简单学习一下用 Go 实现观察者设计模式,给怎么实现事件驱动编程.事件源这些模式做个铺垫.主要也是我也老没看设计模式了,一起再复习一下.以前看的设计模式教程都是 Java 的,这次用 Go 实现一番. 观察者模式 咱们先来看一下观察者模式的概念,我尽量加一些自己的理解,让它变成咱们都能理解的大俗话: 概念 观察者模式 (Observer Pattern),定义对象间的一种一对多依赖关

  • Go语言实现23种设计模式的使用

    目录 创建型模式 工厂方法模式 Factory Method 问题 解决 抽象工厂模式 Abstract Factory 问题 解决 建造者模式 Builder 问题 解决 原型模式 Prototype 问题 解决 单例模式 Singleton 问题 解决 结构型模式 适配器模式 Adapter 问题 解决 桥接模式Bridge 问题 解决 对象树模式Object Tree 问题 解决 装饰模式Decorator 问题 解决 外观模式Facade 问题 解决 享元模式 Flyweight 问题

  • golang实现简单工厂、方法工厂、抽象工厂三种设计模式

    1.简单工厂: 第一步:创建一个文章接口,需要实现阅读和写作的功能. type Article interface { ReadArticle() string WriteArticle(contents string) string } 第二步:创建 中文书 和 英文书 两个“类”,并且分别实现两种方法.(注:golang种没有类,只有组合.应贺总强调,特别说明) type ChineseArticle struct{} type EnglishArticle struct{} func (c

  • Go语言基础设计模式之策略模式示例详解

    目录 概述 针对同一类型问题的多种处理方式 一.不使用策略模式 二.策略模式 UML 总结 示例 概述 定义一系列算法,将每个算法封装起来.并让它们能够相互替换.策略模式让算法独立于使用它的客户而变化. 针对同一类型问题的多种处理方式 一.不使用策略模式 package main import "fmt" type User struct { Name string } func (this User) travel(t string) { switch t { case "

  • Golang设计模式工厂模式实战写法示例详解

    目录 拆出主板 工厂模式流程 代码实战 抽象能力,定义接口 实现工厂,支持注册和获取实现 主流程只依赖接口完成 扩展 => 适配器,实现接口 注册适配器到工厂里 小结 拆出主板 今天带大家看一下怎么用 Go 写工厂模式的代码,我们来学习一个实战案例.这个写法笔者日常经常使用,能够很有效地帮助大家实现 Separation of Concerns. 主板就是一个程序的主流程.比如我们要基于一份学习资料来消化,吸收知识.我们可能有下面几步流程: 准备好笔记本: 打开资料: 阅读资料内容,思考并记录关

  • JavaScript设计模式之原型模式和适配器模式示例详解

    目录 原型模式 原型模式介绍 代码实现 适配器模式 适配器模式介绍 代码实现 小结 原型模式 原型模式介绍 原型模式是指原型实例指向创建对象的种类,并通过拷贝这些原型创建新的对象,是一种用来创建对象的模式,也就是创建一个对象作为另一个对象的prototype属性 实现原型模式是在ECMAScript5中,提出的Object.create方法,使用现有的对象来提供新创建的对象的__proto__. 代码实现 var lynkCoPrototype = { model: "领克", get

  • python模式 工厂模式原理及实例详解

    这篇文章主要介绍了python模式 工厂模式原理及实例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 工厂模式是一个在软件开发中用来创建对象的设计模式. 工厂模式包涵一个超类.这个超类提供一个抽象化的接口来创建一个特定类型的对象,而不是决定哪个对象可以被创建. 为了实现此方法,需要创建一个工厂类创建并返回. 当程序运行输入一个"类型"的时候,需要创建于此相应的对象.这就用到了工厂模式.在如此情形中,实现代码基于工厂模式,可以达到可

  • React路由拦截模式及withRouter示例详解

    目录 一.路由拦截 二.路由模式 三.withRouter 一.路由拦截 在前面两篇 路由博客基础上,我们将ReactRouter.js的我的profile路由设置成路由拦截的: <Route path="/profile" render={() => isAuth() ? <Profile/> : <Redirect to="/login"></Redirect> }></Route> 新建Logi

  • Golang 官方依赖注入工具wire示例详解

    目录 依赖注入是什么 开源选型 wire providers injectors 类型区分 总结 依赖注入是什么 Dependency Injection is the idea that your components (usually structs in go) should receive their dependencies when being created. 在 Golang 中,构造一个结构体常见的有两种方式: 在结构体初始化过程中,构建它的依赖: 将依赖作为构造器入参,传入进

  • golang gorm更新日志执行SQL示例详解

    目录 1. 更新日志 1.1. v1.0 1.1.1. 破坏性变更 gorm执行sql 1. 更新日志 1.1. v1.0 1.1.1. 破坏性变更 gorm.Open返回类型为*gorm.DB而不是gorm.DB 更新只会更新更改的字段 大多数应用程序不会受到影响,只有当您更改回调中的更新值(如BeforeSave,BeforeUpdate)时,应该使用scope.SetColumn,例如: func (user *User) BeforeUpdate(scope *gorm.Scope) {

  • Golang 实现 RTP音视频传输示例详解

    目录 引言 RTP 数据包头部字段 Golang 的相关实现 结尾 引言 在 Coding 之前我们先来简单介绍一下 RTP(Real-time Transport Protocol), 正如它的名字所说,用于互联网的实时传输协议,通过 IP 网络传输音频和视频的网络协议. 由音视频传输工作小组开发,1996 年首次发布,并提出了以下使用设想. 简单的多播音频会议 使用 IP 的多播服务进行语音通信.通过某种分配机制,获取多播组地址和端口对.一个端口用于音频数据的,另一个用于控制(RTCP)包,

  • Golang中的错误处理的示例详解

    目录 1.panic 2.包装错误 3.错误类型判断 4.错误值判断 1.panic 当我们执行panic的时候会结束下面的流程: package main import "fmt" func main() { fmt.Println("hello") panic("stop") fmt.Println("world") } 输出: go run 9.go hellopanic: stop 但是panic也是可以捕获的,我们可

  • Golang实现简单http服务器的示例详解

    目录 一.基本描述 二 .具体方法 2.1 连接的建立 2.2 http请求解析 2.3 http请求处理 2.4 http请求响应 三.完整示例 一.基本描述 完成一个http请求的处理和响应,主要有以下几个步骤: 监听端口 建立连接 解析http请求 处理请求 返回http响应 完成上面几个步骤,便能够实现一个简单的http服务器,完成对基本的http请求的处理 二 .具体方法 2.1 连接的建立 go中net包下有提供Listen和Accept两个方法,可以完成连接的建立,可以简单看下示例

  • Golang实现数据结构Stack(堆栈)的示例详解

    目录 前言 介绍Stack Stack Push Pop Peek Len & Cap & Clear NewStack 使用 前言 始于此篇,为了学习 Golang 基础,采用了使用 Golang 实现各种数据结构,以此来和 Golang 交朋友,今天的主题就是 把Stack介绍给Golang认识 源码:Stack 介绍Stack 在计算机科学中,stack(栈)是一种基本的数据结构,它是一种线性结构,具有后进先出(Last In First Out)的特点. 上述是通过对 ChatGP

随机推荐