前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >设计模式汇总(更新中...)

设计模式汇总(更新中...)

作者头像
素履coder
发布2023-07-11 14:43:35
1320
发布2023-07-11 14:43:35
举报
文章被收录于专栏:素履coder素履coder

1. Go中的面向对象#

面向对象三大特性:封装、继承、多态。

设计模式需遵循面向对象的设计原则,由于本文是通过go语言实现的,所以需要先了解go中的面向对象是怎么样的。

Golang中的面向对象是通过struct结构体实现的,类似于C++和Java中的Class类。其中struct类似C++的普通类类型,interface则对应抽象类类型。对象的成员变量可见性则是通过大小写字母开头来区分。

Golang中的继承是通过组合来实现的,下例基类是Base,子类是Foo;子类可以直接调用基类的公有方法,子类也可以定义自己的属性以及实现自己的方法。

代码语言:javascript
复制
type Base struct {
	Name string
}
func (base *Base) Bar() {
	fmt.Println(base.Name)
}

type Foo struct {
	Base
}
func (foo *Foo) Bar() {
	foo.Base.Bar()
}

func main() {
	f := Foo{Base{Name: "hello"}}
	f.Bar()
}

// hello

Golang中的多态是通过interface实现的,下例通过interface抽象出了不同品牌手机的价格,具体则是通过不同手机品牌的类来实现该手机品牌的价格。

代码语言:javascript
复制
type Phone interface {
	Price() float64
}

type Huawei struct {
	price float64
}
func (h *Huawei) Price() float64 {
	return h.price
}

type Xiaomi struct {
	price float64
}
func (x *Xiaomi) Price() float64 {
	return x.price
}
func NewXiaomiPrice(xiaomi *Xiaomi) Phone {
	return xiaomi
}

func main() {
	h := Huawei{price: 3000}
	fmt.Println(h.Price())
	x := Xiaomi{price: 2000}
	fmt.Println(x.Price())
    nx := NewXiaomiPrice(&Xiaomi{price: 2500})
	fmt.Println(nx.Price())
}

// 3000
// 2000
// 2500

2. 设计模式原则#

2.1 单一职责原则#

即一个类只对应一个职责,其职责是引起该类变化的原因,例如类T1只完成F1的功能,类T2只完成F2的功能,T1改变的时候不会影响F2,同理T2改变的时候不会影响F1,做到职责单一

代码语言:javascript
复制
type T1 struct {}
func (t *T1) F1() {}

type T2 struct {}
func (t *T2) F2() {}

func main() {
	t1 := new(T1)
	t1.F1()
	t2 := new(T2)
	t2.F2()
}

2.2 开闭原则#

开闭原则即对程序的扩展是持开放态度的,对程序的修改是封闭态度的。目的是为了程序的扩展性好,易于维护,减少因为代码的多次修改而造成各种隐性bug,遵循高内聚,低耦合的原则。

在GO语言中需要用到interface字段对方法进行抽象,做到T1业务和Function和T2业务的Function互不影响,而且还可以扩展新业务而不用从之前的Function的修改

代码语言:javascript
复制
type Abstract interface {
	Function()
}

type T1 struct {}
func (t *T1) Function() {
	fmt.Println("t1业务")
}

type T2 struct {}
func (t *T2) Function() {
	fmt.Println("t2业务")
}

func Business(abstract Abstract) {
	abstract.Function()
}

func main() {
	Business(new(T1))	// t1业务
	Business(new(T2))   // t2业务
}

2.3 里氏代换原则#

里氏代换原则规定子类不得重写父类的普通方法,只能重写父类的抽象方法;即子类可以扩展父类的功能,但是不能改变父类原有的功能

2.4 依赖倒转原则#

依赖倒置原则的定义为:高层模块不应该依赖低层模块,而是高层和低层都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。其核心思想是:要面向接口编程,不要面向实现编程。

例如下例就是耦合度极高的一个例子,固定死了peopleA play xiaomi games,peopleB play huawei games,如果我想peopleA play huawei games就还得写结构体类去实现,这样不利于扩展

代码语言:javascript
复制
type Xiaomi struct {}
func (x *Xiaomi) games() {
	fmt.Println("xiaomi games")
}

type Huawei struct {}
func (x *Huawei) games() {
	fmt.Println("huawei games")
}

type PeopleA struct {}
func (p *PeopleA) play(x *Xiaomi)  {
	fmt.Printf("peopleA play ")
	x.games()
}

type PeopleB struct {}
func (p *PeopleB) play(h *Huawei)  {
	fmt.Printf("peopleB play ")
	h.games()
}

func main() {
	x := &Xiaomi{}
	h := &Huawei{}
	a := &PeopleA{}	
	a.play(x) // peopleA play xiaomi games
	b := &PeopleB{} 
	b.play(h) // peopleB play huawei games
}

根据依赖倒转原则改进,人和手机可以分别抽象成两个接口(模块),模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过接口或抽象类产生。下例中如果我想 peopleA play huawei games 可以直接在main函数中调用,而不用像上例还要手动实现类

代码语言:javascript
复制
type People interface {
	play(phone Phone)
}
type Phone interface {
	games()
}

type Xiaomi struct {}
func (x *Xiaomi) games() {
	fmt.Println("xiaomi games")
}

type Huawei struct {}
func (x *Huawei) games() {
	fmt.Println("huawei games")
}

type PeopleA struct {}
func (p *PeopleA) play(x Phone)  {
	fmt.Printf("peopleA play ")
	x.games()
}

type PeopleB struct {}
func (p *PeopleB) play(h Phone)  {
	fmt.Printf("peopleB play ")
	h.games()
}

func main() {
	x := &Xiaomi{}
	h := &Huawei{}
	pa := &PeopleA{} 
	pb := &PeopleB{} 
	pa.play(x) // peopleA play xiaomi games
	pb.play(h) // peopleB play huawei games
}

2.5 接口隔离原则#

客户端不应该依赖它不需要的接口。一个类对另一个类的依赖应该建立在最小的接口上。简单地说,就是使用多个专门的接口比使用单个接口要好很多。

2.6 合成复用原则#

如果使用继承,会导致父类的任何变换都可能影响到子类的行为,所以优先使用组合的方式代替继承的方式。

2.7 迪米特法则#

又叫最少知道原则,一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立;降低类之间的耦合度,提高模块的相对独立性

3. 设计模式#

3.1 创建型模式#

3.1.1 工厂方法模式#

抽象工厂接口+具体工厂+抽象产品接口+具体产品

优点:一个调用者想创建一个对象,只要知道其名称就可以了,易扩展

缺点:每次增加具体产品时需要新增实现,增加了代码量和复杂度

代码语言:javascript
复制
type Phone interface {
	Show()
}

type AbstractFactory interface {
	ProducePhone() Phone
}

// 手机模块
type Xiaomi struct {}
func (x *Xiaomi) Show()  {
	fmt.Println("xiaomi")
}

type Huawei struct {}
func (h *Huawei) Show()  {
	fmt.Println("huawei")
}

// 手机工厂模块
type XiaomiFactory struct {}
func (x *XiaomiFactory) ProducePhone() Phone {
	return new(Xiaomi)
}

type HuaweiFactory struct {}
func (h *HuaweiFactory) ProducePhone() Phone {
	return new(Huawei)
}

func main() {
	f1 := new(XiaomiFactory)
	f1.ProducePhone().Show() // 生产小米手机

	f2 := new(HuaweiFactory)
	f2.ProducePhone().Show() // 生产华为手机
}
3.1.2 抽象工厂模式#

在工厂方法模式中,每一个工厂只生产一类产品,导致大量工厂类的存在。

因此抽象工厂模式在工厂的维度又抽象了一层,使得增加新的产品族时(如增加一个厂商)方便,但是当新增产品等级结构(如Intel厂商下新增其他配件)时会修改原来的抽象层代码,违背了开闭原则;因此抽象工厂模式适用于产品族较多,且每一个产品族内的产品等级结构稳定的情况。

用抽象工厂模式实现下面例子:

设计一个电脑主板架构,电脑包括(显卡,内存,CPU)3个固定的插口,显卡具有显示功能(display,功能实现只要打印出意义即可),内存具有存储功能(storage),cpu具有计算功能(calculate)。现有Intel厂商,nvidia厂商,Kingston厂商,均会生产以上三种硬件。要求组装两台电脑:

  • 1台(Intel的CPU,Intel的显卡,Intel的内存)
  • 1台(Intel的CPU, nvidia的显卡,Kingston的内存)
代码语言:javascript
复制
// 抽象层
type AbstractGPU interface {
	Display()
}
type AbstractCPU interface {
	Calculate()
}
type AbstractMemory interface {
	Storage()
}

// 抽象工厂
type AbstractFactory interface {
	CreateGPU() AbstractGPU
	CreateCPU() AbstractCPU
	CreateMemory() AbstractMemory
}
代码语言:javascript
复制
// Intel 厂商
type IntelGPU struct{}
type IntelCPU struct{}
type IntelMemory struct{}
type IntelFactory struct{}

func (i *IntelGPU) Display() {
	fmt.Printf("Intel GPU display,")
}
func (i *IntelCPU) Calculate() {
	fmt.Printf("Intel CPU calculate,")
}
func (i *IntelMemory) Storage() {
	fmt.Printf("Intel memory storage,")
}
func (i *IntelFactory) CreateIntelGPU() AbstractGPU {
	return new(IntelGPU)
}
func (i *IntelFactory) CreateIntelCPU() AbstractCPU {
	return new(IntelCPU)
}
func (i *IntelFactory) CreateIntelMemory() AbstractMemory {
	return new(IntelMemory)
}
代码语言:javascript
复制
// Nvidia 厂商
type NvidiaGPU struct{}
type NvidiaCPU struct{}
type NvidiaMemory struct{}
type NvidiaFactory struct{}

func (n *NvidiaGPU) Display() {
	fmt.Printf("Nvidia GPU display,")
}
func (n *NvidiaCPU) Calculate() {
	fmt.Printf("Nvidia CPU calculate,")
}
func (n *NvidiaMemory) Storage() {
	fmt.Printf("Nvidia memory storage,")
}
func (n *NvidiaFactory) CreateNvidiaGPU() AbstractGPU {
	return new(NvidiaGPU)
}
func (n *NvidiaFactory) CreateNvidiaCPU() AbstractCPU {
	return new(NvidiaCPU)
}
func (n *NvidiaFactory) CreateNvidiaMemory() AbstractMemory {
	return new(NvidiaMemory)
}
代码语言:javascript
复制
// Kingston 厂商
type KingstonGPU struct{}
type KingstonCPU struct{}
type KingstonMemory struct{}
type KingstonFactory struct{}

func (k *KingstonGPU) Display() {
	fmt.Printf("Kingston GPU display,")
}
func (k *KingstonCPU) Calculate() {
	fmt.Printf("Kingston CPU calculate,")
}
func (k *KingstonMemory) Storage() {
	fmt.Printf("Kingston memory storage,")
}
func (k *KingstonFactory) CreateKingstonGPU() AbstractGPU {
	return new(KingstonGPU)
}
func (k *KingstonFactory) CreateKingstonCPU() AbstractCPU {
	return new(KingstonCPU)
}
func (k *KingstonFactory) CreateKingstonMemory() AbstractMemory {
	return new(KingstonMemory)
}
代码语言:javascript
复制
func main() {
	// Intel的CPU,Intel的显卡,Intel的内存
	intelFac := new(IntelFactory)
	intelFac.CreateIntelCPU().Calculate()
	intelFac.CreateIntelGPU().Display()
	intelFac.CreateIntelMemory().Storage()
	fmt.Println()

	// Intel的CPU, nvidia的显卡,Kingston的内存
	nvidiaFac := new(NvidiaFactory)
	kingstonFac := new(KingstonFactory)
	intelFac.CreateIntelCPU().Calculate()
	nvidiaFac.CreateNvidiaGPU().Display()
	kingstonFac.CreateKingstonMemory().Storage()
}
3.1.3 单例模式#

定义:保证一个类、只有一个实例存在,同时提供能对该实例访问的全局访问方法

代码语言:javascript
复制
var once sync.Once
var singleInstance *single

type single struct{}	// 首字母小写,不对外暴露

func GetSingleInstance() *single {
	if singleInstance == nil {
		once.Do(func() { // 只会执行一次,即使在并发的情况下
			fmt.Println("Create single instance.")
			singleInstance = &single{}
		})
	} else {
        // 之后使用已创建的实例
		fmt.Println("Get single instance.")
	}
	return singleInstance
}

func main() {
	for i := 0; i < 10; i++ {
		go GetSingleInstance()
	}
	time.Sleep(time.Second * 60)
}

// Create single instance.
// Get single instance.
// Get single instance.

3.2 结构型模式#

3.3 行为模式#

4. 参考链接#

[1]. Title https://www.bilibili.com/video/BV1Eg411m7rV/?spm_id_from=333.999.0.0

[2]. Title https://refactoringguru.cn/

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-06-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. Go中的面向对象#
  • 2. 设计模式原则#
    • 2.1 单一职责原则#
      • 2.2 开闭原则#
        • 2.3 里氏代换原则#
          • 2.4 依赖倒转原则#
            • 2.5 接口隔离原则#
              • 2.6 合成复用原则#
                • 2.7 迪米特法则#
                • 3. 设计模式#
                  • 3.1 创建型模式#
                    • 3.1.1 工厂方法模式#
                    • 3.1.2 抽象工厂模式#
                    • 3.1.3 单例模式#
                  • 3.2 结构型模式#
                    • 3.3 行为模式#
                    • 4. 参考链接#
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档