这些Coding套路你不会还不知道吧?

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 这些Coding套路你不会还不知道吧?

对于一名程序员来说,编码进阶是成为优秀工程师非常重要的一步,它可以让我们更加熟练地掌握编程,深入理解数据结构和算法,从而更好地完成复杂的任务,提高工作效率。而我认为熟练使用设计模式就是编码进阶的最好方式之一,下面就用一篇文章来分享下Go开发中常用的设计模式。

  • 1️⃣全局单一实例:单例模式
  • 🚗获取对象超简单:工厂模式
  • 📋重复代码太多?试试:模板方法模式
  • 👻接口对应功能不知道怎么维护?这里有:策略模式
  • 🎈独特好玩的Functional Options模式

What?Why?

从两个问题开始今天的分享:

设计模式是什么?

简单来讲,就两个字:套路,编码的套路,在我们写代码的时候这个套路可以不用,但是不能不知道。

为什么要使用设计模式?

设计模式是一种被反复使用的,针对软件设计中常见问题的可复用解决方案。它们提供了一种经过验证的方式来解决复杂的设计问题,并帮助开发人员编写更加清晰、可维护和可扩展的代码

使用设计模式的好处包括:

  1. 提高代码的可读性和可维护性。通过使用设计模式,开发人员可以将复杂的问题分解成更小、更易于管理的部分,并且可以将这些部分组织成一致的、易于理解的代码结构。
  2. 提高代码的可重用性。设计模式提供了一种标准化的解决方案,可以让相同的功能代码在多个地方重复使用,从而避免了重复编写相同的代码,减少了开发时间和成本。
  3. 提高代码的灵活性和扩展性。设计模式允许开发人员在不改变现有代码的情况下,轻松地添加新的功能或修改现有的功能。

常见的设计模式实践

1 全局单一实例:单例模式

首先,单例模式一般用于以下业务场景:

(1)整个程序的运行中只允许有一个类的实例。

(2)创建对象时耗时过多或者耗资源过多,但又经常用到的。

(3)需要全局访问并保证线程安全的对象。

(4)需要保持状态的对象。

具体场景:

数据库连接对象。我们在具体的项目中往往每种数据库驱动只会使用它的一个实例,因此在这里我们就能够使用单例模式。

代码:

import "sync"
type MysqlConn struct {
  Addr string
}
var (
  mysqlConn *MysqlConn
  once = sync.Once{}
)
func GetMySQLConn() *MysqlConn {
  once.Do(func() {
    mysqlConn = &MysqlConn{Addr: "127.0.0.1"}
  })
  return mysqlConn
}
2 获取对象超简单:工厂模式

工厂模式通常应用于以下场景:

(1)当一个系统需要灵活地配置一组对象,并且需要动态地选择其中的一个时。

(2)当一个类需要频繁地创建和销毁时,可以使用工厂模式来提高性能。

具体场景:

简单来讲就是想要获取一个实例,但是这个实例的属性可能会随着参数的变化而具有不同的形态,还可以用数据库连接来举例,我们有多个服务器可以进行连接,但是每次只能连接一个,而且连接的时候可以填写自己的认证账密。

代码:

type DB struct {
   Addr, UserName, Passwd string
}
func NewMysqlConn(addr, userName, passwd string) *DB {
   return &DB{
      Addr:     addr,
      UserName: userName,
      Passwd:   passwd,
   }
}
3 重复代码太多?试试:模板方法模式

模板方法模式通常应用于以下场景:

(1)当一个算法的步骤中有一部分是不变的,而另一部分是需要根据不同的条件进行变化时,可以使用模板方法模式来实现。

(2)当一个类的子类需要实现一个接口的不同版本时,可以使用模板方法模式来实现。

具体场景:

做水果酸奶,水果或其他食材是统一的抽象,而火龙果、芒果、饼干都是具体,因为不管用什么水果或食材来做,做法都是如出一辙的,所以做法也是一个抽象,这就好比一个模板,对,就是模版方法模式。

代码:

import (
   "fmt"
   "testing"
)
type MakeYogurtTemplate interface {
  CreateYogurt() //准备好酸奶
  CutFruit()     //切水果
  Merge()        //放在一起搅拌
  Optimize()     //调制味道
  Eating()       //开吃
  Do()
}
type DragonFruit struct {
}
func (d *DragonFruit) CreateYogurt() {
   fmt.Println("用鲜奶和乳酸菌发酵好酸奶")
}
func (d *DragonFruit) CutFruit() {
   fmt.Println("把火龙果切成块块")
}
func (d *DragonFruit) Merge() {
   fmt.Println("放在一起进行搅拌")
}
func (d *DragonFruit) Optimize() {
   fmt.Println("调制出自己喜欢的味道")
}
func (d *DragonFruit) Eating() {
   fmt.Println("开吃")
}
func (d *DragonFruit) Do() {
   d.CreateYogurt()
   d.CutFruit()
   d.Merge()
   d.Optimize()
   d.Eating()
}
func TestDragonFruit(t *testing.T) {
   d := &DragonFruit{}
   d.Do()
}
type Mango struct {
}
func (m *Mango) CreateYogurt() {
   fmt.Println("用鲜奶和乳酸菌发酵好酸奶")
}
func (m *Mango) CutFruit() {
   fmt.Println("把芒果切成块块")
}
func (m *Mango) Merge() {
   fmt.Println("放在一起进行搅拌")
}
func (m *Mango) Optimize() {
   fmt.Println("调制出自己喜欢的味道")
}
func (m *Mango) Eating() {
   fmt.Println("开吃")
}
func (m *Mango) Do() {
   m.CreateYogurt()
   m.CutFruit()
   m.Merge()
   m.Optimize()
   m.Eating()
}
func TestMango(t *testing.T) {
   m := &Mango{}
   m.Do()
}
4 接口对应功能不知道怎么维护?这里有:策略模式

策略模式通常在一个系统中需要多个算法,并且这些算法需要在不同的时间或条件下使用不同的算法时,可以使用策略模式来实现。

具体场景:

对于新手程序员同学经常会有这样的选择,到底是学Go还是学Java,这显然是两种不同的策略选择,但是不管是学习哪一个的基本流程都是差不多的,比如都是先准备学习资料,然后在学习和实践,因此可以基于此使用策略模式来形容。

代码:

策略抽象

type Learn interface {
   PrepareData()
   DoLearn()
   Play()
}
func LearnLang(l Learn) {
   l.PrepareData()
   l.DoLearn()
   l.Play()
}

策略1

import "fmt"
type LikeGo struct {
}
func (g *LikeGo) PrepareData() {
   fmt.Println("准备Go资料")
}
func (g *LikeGo) DoLearn() {
   fmt.Println("学习Go")
}
func (g *LikeGo) Play() {
   fmt.Println("玩转Go语言")
}

策略2

import "fmt"
type LikeJava struct {
}
func (g *LikeJava) PrepareData() {
   fmt.Println("准备Java资料")
}
func (g *LikeJava) DoLearn() {
   fmt.Println("学习Java")
}
func (g *LikeJava) Play() {
   fmt.Println("玩Java")
}

执行策略

import "testing"
func TestLearn(t *testing.T) {
   likeGo := &LikeGo{}
   LearnLang(likeGo)
}
5 独特好玩的Functional Options模式

Functional Options模式通常在当一个对象或函数具有多个参数时,这些参数可能会有不同的默认值或取值范围。通过将它们作为函数的选项传递,可以更灵活地控制函数的行为

具体场景:

gRPC服务进行实例化的时候有些参数可以不同填,即选填,之后在源码内部会使用默认的值,于是我们就可以使用以下的方式进行处理。

代码:

import "time"
type RpcServer struct {
   Name    string
   MaxConn int
   Address []string
   TimeOut time.Duration
}
type RpcServerOption func(server *RpcServer)
func WithName(name string) RpcServerOption {
   return func(server *RpcServer) {
      server.Name = name
   }
}
func WithMaxConn(max int) RpcServerOption {
   return func(server *RpcServer) {
      server.MaxConn = max
   }
}
func WithAddress(addr []string) RpcServerOption {
   return func(server *RpcServer) {
      server.Address = addr
   }
}
func WithTimeOut(timeout time.Duration) RpcServerOption {
   return func(server *RpcServer) {
      server.TimeOut = timeout
   }
}
func NewRpcServer(opts ...RpcServerOption) *RpcServer {
   server := &RpcServer{}
   for _, opt := range opts {
      opt(server)
   }
   return server
}

实例化:

import (
   "fmt"
   "testing"
   "time"
)
func TestCreateRpcServerByOptions(t *testing.T) {
   rpcServer := NewRpcServer(
      WithAddress([]string{"127.0.0.1"}),
      WithName("rpcServer"),
      WithMaxConn(1),
      WithTimeOut(time.Second),
   )
   fmt.Println(*rpcServer)
}

小总结

本文主要介绍了Go开发中常用的设计模式,包括全局单一实例:单例模式、工厂模式、模板方法模式、策略模式和Functional Options模式。这些设计模式可以帮助我们更好地组织代码,提高代码的可读性和可重用性。

总之,掌握这些设计模式对于提高Go程序员的编码能力非常有帮助,可以让我们在编写代码时更加得心应手,同时也能提高代码的质量和可维护性。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
7月前
|
中间件 数据库连接 API
Python面试:FastAPI框架原理与实战
【4月更文挑战第18天】FastAPI是受欢迎的高性能Python Web框架,以其简洁的API设计、强大的类型提示和优秀的文档生成能力著称。本文将探讨FastAPI面试中的常见问题,包括路由、响应对象、Pydantic模型、数据库操作、中间件和错误处理。同时,还会指出一些易错点,如类型提示不准确、依赖注入误解,并提供实战代码示例。通过理解和实践FastAPI,可以在面试中展示出色的Web开发技能。
197 1
|
机器学习/深度学习 人工智能 Java
Python面试可能会问到的问题,你会几个?
Python面试可能会问到的问题,你会几个?
121 0
|
2月前
|
搜索推荐 Python
Leecode 101刷题笔记之第五章:和你一起你轻松刷题(Python)
这篇文章是关于LeetCode第101章的刷题笔记,涵盖了多种排序算法的Python实现和两个中等难度的编程练习题的解法。
24 3
|
2月前
|
算法 C++ Python
Leecode 101刷题笔记之第四章:和你一起你轻松刷题(Python)
这篇博客是关于LeetCode上使用Python语言解决二分查找问题的刷题笔记,涵盖了从基础到进阶难度的多个题目及其解法。
21 0
|
2月前
|
算法 C++ Python
Leecode 101刷题笔记之第三章:和你一起你轻松刷题(Python)
本文是关于LeetCode算法题的刷题笔记,主要介绍了使用双指针技术解决的一系列算法问题,包括Two Sum II、Merge Sorted Array、Linked List Cycle II等,并提供了详细的题解和Python代码实现。
15 0
|
5月前
|
算法 Java Linux
python中的面试常考知识点
python中的面试常考知识点
|
7月前
|
数据采集 算法 网络协议
最新Python 面试常见问题(1),2024年最新面试官必问的10个问题
最新Python 面试常见问题(1),2024年最新面试官必问的10个问题
最新Python 面试常见问题(1),2024年最新面试官必问的10个问题
|
7月前
|
程序员
如何写出高质量的C代码?快来学习这些coding技巧
如何写出高质量的C代码?快来学习这些coding技巧
|
7月前
|
SQL 分布式计算 算法
10个Python面试常问的问题_python面试中的常问问题(1),2024年最新搜狐面试难吗
10个Python面试常问的问题_python面试中的常问问题(1),2024年最新搜狐面试难吗
|
7月前
|
UED Python
掌握Python异常处理:面试中的关键考点
【4月更文挑战第14天】本文探讨了Python异常处理在面试中的重要性,涵盖核心概念、常见问题和易错点。异常处理涉及异常、捕获、异常链、自定义异常、finally子句和raise语句。面试中应注意避免过于宽泛的异常捕获、忽视异常链、在finally中误用return、自定义异常设计不实用以及异常处理与业务逻辑混杂等问题。通过理解并解决这些问题,可提升代码健壮性和面试表现。
96 0