百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

Go设计模式(1)-语法(gof常用设计模式)

ccwgpt 2024-10-10 04:51 30 浏览 0 评论

简介

最近思考了一下这几年写的业务,都是用面向过程思路来实现。之所以用面向过程

一是因为大家都这么写,很少去思考是否有更好的实现

二是业务简单,使用面向过程编程可以很方便的实现

三是业务需要快速上线,面向过程的方法更快更直接

但是弊端也很明显,随着业务不断的积累,项目改动起来比较困难,需要不断梳理前人是怎么写的、有什么影响,测试需要做大量的测试,确保功能是正常的。有时候即使是相似或者迭代性的需求也无法保证快速上线。而且即使耗费了大量的人力,也很难保证没有遗漏。这时候就想起面向对象的好。

四大特性

面向对象编程有四大特性

  1. 封装特性封装也叫作信息隐藏或者数据访问保护。类通过暴露有限的访问接口,授权外部仅能通过类提供的方式来访问内部信息或者数据。它需要编程语言提供权限访问控制语法来支持,例如Java中的private、protected、public关键字。封装特性存在的意义,一方面是保护数据不被随意修改,提高代码的可维护性;另一方面是仅暴露有限的必要接口,提高类的易用性。
  2. 抽象特性封装主要讲如何隐藏信息、保护数据,那抽象就是讲如何隐藏方法的具体实现,让使用者只需要关心方法提供了哪些功能,不需要知道这些功能是如何实现的。抽象可以通过接口类或者抽象类来实现,但也并不需要特殊的语法机制来支持。抽象存在的意义,一方面是提高代码的可扩展性、维护性,修改实现不需要改变定义,减少代码的改动范围;另一方面,它也是处理复杂系统的有效手段,能有效地过滤掉不必要关注的信息。
  3. 继承特性继承是用来表示类之间的is-a关系,分为两种模式:单继承和多继承。单继承表示一个子类只继承一个父类,多继承表示一个子类可以继承多个父类。为了实现继承这个特性,编程语言需要提供特殊的语法机制来支持。继承主要是用来解决代码复用的问题。
  4. 多态特性多态是指子类可以替换父类,在实际的代码运行过程中,调用子类的方法实现。多态这种特性也需要编程语言提供特殊的语法机制来实现,比如继承、接口类、duck-typing。多态可以提高代码的扩展性和复用性,是很多设计模式、设计原则、编程技巧的代码实现基础。

实现

想要用面向对象编程来实现业务逻辑,必然需要掌握的是如何使用这门语言实现四大特性。在掌握了这份知识的基础上,才有可能灵活的使用设计模式,设计出好的架构。今后学习新的语言的时候,对于面向对象的实现,需要成为关注点之一。看下面的内容需要掌握基本的Go语言知识。

封装

Go中封装的实现方法为使用结构体,并给结构体添加相应的方法。

一般的实现步骤如下:

  1. 将结构体、字段的首字母小写;
  2. 给结构体所在的包提供一个工厂模式的函数,首字母大写,类似一个构造函数;
  3. 提供一个首字母大写的Set方法(类似其它语言的public),用于对属性判断并赋值;
  4. 提供一个首字母大写的Get方法(类似其它语言的public),用于获取属性的值。

举例:对于员工,不能随便查看年龄,工资等隐私,并对输入的年龄进行合理的验证。代码结构如下

package model

import "fmt"

type person struct {
   Name string
   age  int //其它包不能直接访问..
   sal  float64
}

//写一个工厂模式的函数,相当于构造函数
func NewPerson(name string) *person {
   return &person{
      Name: name,
   }
}

//为了访问age 和 sal 我们编写一对SetXxx的方法和GetXxx的方法
func (p *person) SetAge(age int) {
   if age > 0 && age < 150 {
      p.age = age
   } else {
      fmt.Println("年龄范围不正确..")
      //给程序员给一个默认值
   }
}
func (p *person) GetAge() int {
   return p.age
}

func (p *person) SetSal(sal float64) {
   if sal >= 3000 && sal <= 30000 {
      p.sal = sal
   } else {
      fmt.Println("薪水范围不正确..")
   }
}

func (p *person) GetSal() float64 {
   return p.sal
}

关于这个代码,有两点需要说明

1.关于大小写

  • 小写字母开头的函数只在本包内可见,大写字母开头的函数才能被其他包使用。这个规则也适用于类型和变量的可见性。
  • 大小写影响了可见性,大写字母开头等同于public,小写字母开头等同于private,这种做法不仅免除了public、private关键字,更重要的是统一了命名风格。

2.结构体方法参数

  • 如果要求对象必须以指针传递,这有时会是个额外成本,因为对象有时很小(比如4字节),用指针传递并不划算。
  • 只有在你需要修改对象的时候,才必须用指针。

继承

Go语言根本就不支持面向对象思想中的继承语法。

从另一个维度而言,Go语言也提供了继承,但是采用了组合的文法,所以我们将其称为匿名组合。

举例:

package main

import "fmt"

type Base struct {
   Name string
}

func (b *Base) SetName(name string) {
   b.Name = name
}

func (b *Base) GetName() string {
   return b.Name
}

// 组合,实现继承
type Child struct {
   base Base // 这里保存的是Base类型
}

// 重写GetName方法
func (c *Child) GetName() string {
   c.base.SetName("modify...")
   return c.base.GetName()
}

// 实现继承,但需要外部提供一个Base的实例
type Child2 struct {
   base *Base // 这里是指针
}

//
type Child3 struct {
   Base
}

type Child4 struct {
   *Base
}

func main() {
   c := new(Child)
   c.base.SetName("world")
   fmt.Println(c.GetName())

   c2 := new(Child2)
   c2.base = new(Base) // 因为Child2里面的Base是指针类型,所以必须提供一个Base的实例
   c2.base.SetName("ccc")
   fmt.Println(c2.base.GetName())

   c3 := new(Child3)
   c3.SetName("1111")
   fmt.Println(c3.GetName())

   c4 := new(Child4)
   c4.Base = new(Base)
   c4.SetName("2222")
   fmt.Println(c4.GetName())
}

关于这段代码,有几点需要说明

  1. 可以使用匿名组合和非匿名组合,如果使用非匿名组合,则调用的时候需要显示指定变量名称。如果使用匿名组合,则无需显示指定变量名称,当然也可以显示调用,如c3.Base.Name。
  2. 在Go语言中,还可以以指针方式从一个类型“派生”:如Child4,这段Go代码仍然有“派生”的效果,只是Child4创建实例的时候,需要外部提供一个Base类实例的指针。
  3. 在“派生类”Child3没有改写“基类”Base的成员方法时,相应的方法就被“继承”,例如在上面的例子中,调用c3.GetName()和调用c3.Base.GetName()效果一致。在“派生类”Child改写“基类”Base的成员方法,c.GetName()会调用派生类的方法,如果想调用基类的方法,可以显示调用。
  4. 如果“派生类”和“基类”有相同的变量名Name,所有的派生类的Name成员的访问都只会访问到最外层的那个Name变量,基类的Name变量相当于被覆盖了,可以用显示引用。

多态

在Go语言中,一个类只需要实现了接口要求的所有函数,我们就说这个类实现了该接口。如果类实现了接口,便可将对象实例赋值给接口。

举例:

package main

import "fmt"

type Money interface {
   show() string
}

type OldMoney struct {
}

func (oldMoney *OldMoney) show() string {
   return "I am old money"
}

type NewMoney struct {
}

func (newMoney *NewMoney) show() string {
   return "I am new money"
}

func PrintMoney(l []Money) {
   for _, item := range l {
      fmt.Println(item.show())
   }
}

func main() {
   moneyList := []Money{new(OldMoney), new(NewMoney), new(OldMoney)}
   PrintMoney(moneyList)
}

关于这段代码,有几点需要说明:

  1. 接口赋值并不要求两个接口必须等价。如果接口A的方法列表是接口B的方法列表的子集,那么接口B可以赋值给接口A。
  2. Go语言可以根据下面的函数:func (oldMoney OldMoney) show() string自动生成一个新的show()方法:func (oldMoney *OldMoney) show() string,所以赋值时使用引用还是对象,需要考虑函数参数的类型。

结论

简单梳理了一下Go语言的特性,使用Go做面向对象编程及其简单。后面会用Go实现23设计模式。

资料

  1. Go语言中 封装的理解和实现细节 (Golang经典编程案例)https://blog.csdn.net/cui_yonghua/article/details/94346590
  2. golang继承与接口https://www.cnblogs.com/ExMan/p/11773843.html
  3. golang继承https://studygolang.com/articles/12114
  4. Golang组合和匿名的区别https://blog.csdn.net/wangkai_123456/article/details/107894993
  5. 二十七.golang的多态

最后

大家如果喜欢我的文章,可以关注我的公众号(程序员麻辣烫)

我的个人博客为:https://shidawuhen.github.io/

技术

  1. MySQL开发规范
  2. HTTPS配置实战
  3. Go通道实现原理
  4. Go定时器实现原理
  5. HTTPS连接过程
  6. 限流实现2
  7. 秒杀系统
  8. 分布式系统与一致性协议
  9. 微服务之服务框架和注册中心
  10. Beego框架使用
  11. 浅谈微服务
  12. TCP性能优化
  13. 限流实现1
  14. Redis实现分布式锁
  15. Golang源码BUG追查
  16. 事务原子性、一致性、持久性的实现原理
  17. CDN请求过程详解
  18. 常用缓存技巧
  19. 如何高效对接第三方支付
  20. Gin框架简洁版
  21. InnoDB锁与事务简析
  22. 算法总结

读书笔记

  1. 原则
  2. 资治通鉴
  3. 敏捷革命
  4. 如何锻炼自己的记忆力
  5. 简单的逻辑学-读后感
  6. 热风-读后感
  7. 论语-读后感
  8. 孙子兵法-读后感

思考

  1. 服务端团队假期值班方案
  2. 项目流程管理
  3. 对项目管理的一些看法
  4. 对产品经理的一些思考
  5. 关于程序员职业发展的思考
  6. 关于代码review的思考
  7. Markdown编辑器推荐-typora

相关推荐

css布局方案汇总(28个实例图文并茂)

简介布局在我们前端日常开发来说是非常重要的,一个好的布局能简化代码的同时还能提高网页的性能。常见的布局方法有浮动(float)布局、绝对定位(position)布局、表格布局(table)、弹性(fl...

十款免费的CSS框架加速Web开发

Pure这是Yahoo最新推出的一款CSS框架,它只有HTML和CSS,没有使用任何JavaScript语言。总大小只有4.4kb,但功能却非常丰富,支持响应式样式和各种导航、表格、表单、按钮、网格和...

Tailwind CSS 是不是目前世上最好的CSS框架?

转载说明:原创不易,未经授权,谢绝任何形式的转载今天看了一篇国外大佬对TailwindCSS的看法,在这里分享给大家,看看大家是否赞同,以下是其相关内容的整理,由于翻译水平有限,欢迎大家讨论和指...

下一代 CSS 框架:Mojo CSS,为何如此受欢迎?

TailwindCSS推出即受到广大开发者的欢迎,当前Githubstar数已达77.8k。它是一个功能类优先(utility-first)的CSS框架,它提供了一系列功能类,让开发者...

常见的几种摄影构图方式

摄影构图,是一种在摄影画面中表现结构美、形式美的方式。构图能让摄影主体更加突出,画面更加有序。所以说,构图在摄影中是非常重要的一个环节。无论是前期构图还是后期构图,摄影者都要对构图有一个比较深的了解。...

风光摄影10大构图技巧,会用构图,照片更容易好看

风光摄影10大构图技巧,会用构图,照片更容易好看先解释一下,为什么会使用构图之后,照片更容易好看?因为,构图是根据很多好看的照片,总结出来的技巧,使用这些构图技巧,就相当于站在了巨人的肩膀上,也就是用...

掌握框式构图的摄影技巧,会让摄影爱好者的作品更有魅力!

很多摄影爱好者都知道摄影构图中有个框式构图,但大多数人对框式构图的摄影技巧,却一知半解。所以摄影爱好者们有必要更全面、深入的了解,并掌握框式构图,会对你摄影水平的提高更有帮助。【欢迎点击上方关注:金立...

这个构图很简洁,但为什么不耐看?

摄影爱好者最常犯的错就是过于复杂、主体不明确,但当遇到简单的场景往往又会出现单调、不耐看的状况。为什么会这样?说白了还是观察力不够。下面是本周的摄影入围习作,我们一起来看看这些照片中主体、陪体以及背景...

初学者需要记牢的八种常用构图法

作者:冯海军摄影中,构图很关键,决定照片是否成功,所以在构图上要加以重视和推敲,虽然说构图无定法,但是也有很多的规律可循,以下列举几种常用构图,会对初学者有很大的帮助。多彩刘卫洲摄苏州姑苏俱乐部(...

构图这件事不难!掌握14种构图模式就稳了

如果说视觉元素是视觉信息的载体,那么构图就是视觉元素的载体。没有适当形式的构图对视觉元素有机、有序地承载,平面设计将无法传达预定的设计意图和视觉信息。因此,对于平面设计而言,构图是平面设计不可或缺的重...

框架构图如何使用?

1分钟教你用手机拍大片。今天我们利用框架构图,在不同的运镜方法下拍摄。·首先将手机贴近地面,拍摄人物走过的画面。·然后利用3D效果的背景衬托,将手机贴近地面,以低角度仰拍人物。·最后我们用高清画质来呈...

面构图的5种超实用的构图形式 前景构图,框架构图,填充构图

面构图的5种超实用的构图形式。为什么有的人拍摄的照片好看又舒适?仔细观察会发现他们善用构图。大家好,今天带大家了解摄影中5种超实用的面构图形式。·一、前景构图。前景是构图中的神奇要素,可以提升照片的表...

一看就懂!跟着马格南的大师学构图

马格南图片社是迄今为止全球最重要的摄影图片社,其网站包涵了太多经典的名字和照片。细细品味这些经典图片,能够学到很多有用的构图手法。跟着大师走,总不会错吧?前后景的运用这似乎是非常常见的一种手法,仔细看...

这才是框架构图,有想法!能给你启发么?

框架构图大家并不陌生,但并不是有一个框就行了。框架构图用得不好,就很死板生硬,给人感觉很假。如果你理解透了,拍出的作品不会单调。今天就给大家分享一下框架构图,你看看有哪些妙用?1.广角与长焦的应用长焦...

7B小模型写好学术论文,新框架告别AI引用幻觉

ScholarCopilot团队投稿量子位|公众号QbitAI学术写作通常需要花费大量精力查询文献引用,而以ChatGPT、GPT-4等为代表的通用大语言模型(LLM)虽然能够生成流畅文本,但...

取消回复欢迎 发表评论: