【Day 28】Design Patterns with Go II:Prototype, Singleton, Facade

今天稍微提一下 design patterns 的分类,
也看看设计模式:Prototype, Singleton, Facade 的 Go 程序码
ㄚ,Prototype 的 Go 实作细节没看懂,之後有机会再补吧

  • 程序码都来自 golang-design-pattern,注解是我自己改的,希望有更好理解一些。
  • Refactoring Guru 的 DESIGN PATTERNS 网页写得很不错,很系统化在介绍一个 pattern 的优缺点 / 如何实作 / 跟其他 pattern 的关系

Design Patterns 的分类

Design patterns 可以分为三大类:Creational / Structural / Behavioral,
虽然看了解释但感受还没那麽深,可参考 The Catalog of Design Patterns
其中这几天,提到的都是 creational 类型的 design patterns,
而今天只有 Facade 是 behavioral。

Prototype(原型模式)

复制已经存在的物件,然後稍微改一点东西。

[Design Pattern] Prototype 原型模式 这边提到 Prototype Pattern 非常适合用在有深层结构而且高度自定义的物件上面,在这种情况下你通常不会想从头建立这些物件,另一方面也可以提高程序码的可读性。

Go 实作 07_prototype 还没看很懂,先不放上来了

Singleton(单例模式)

确保一个 class 只能产生一个 instance

可能要存取某个共享的资源,例如资料库或档案。

Go 没有物件,用大写表示 public 小写表示 private

import "sync"

type Singleton interface {
	foo()
}

type singleton struct{}

// foo 表示这个 singleton 的 private function
func (s singleton) foo() {}

// 宣告 instance
var (
	instance *singleton
	once     sync.Once
)

// 外部可呼叫 GetInstance 获得 singleton instance
func GetInstance() Singleton {
	once.Do(func() {
		instance = &singleton{}
	})

	return instance
}

至於其他细节参考 Singleton

Facade(外观模式)

主要是提供一个 interface 供外界操作,但把内部复杂的子系统隐藏起来

以下面的程序码来说,若A、B api 有更新异动,则去更改 facade 实作 apiImplTest()
也就是外部 client 依赖於这层 facade interface,而自己不需要知道内部子系统(A、B api)的逻辑。

本来不太理解为什麽要抽出来一层,但後来想想如果是别的程序要用那就很合理呢,如果某个功能背後会用到不同的第三方库或工具,那写好一个 facade interface,就能在很多地方实体化这个好懂好用的 facade,而不用每次用到类似功能还需要再理解一次这些复杂的子系统。
可以参考 Facade 中的 VideoConverter 范例

facade interface 宣告与实作

func NewAPI() API {
	return &apiImpl{
		a: NewAModuleAPI(),
		b: NewBModuleAPI(),
	}
}

//API is facade interface of facade package
type API interface {
	Test() string
}

//facade implement
type apiImpl struct {
	a AModuleAPI
	b BModuleAPI
}

func (a *apiImpl) Test() string {
	aRet := a.a.TestA()
	bRet := a.b.TestB()
	return fmt.Sprintf("%s\n%s", aRet, bRet)
}

AModule 宣告与实作

这里让 NewAModuleAPI 是大写,所以其实 client 也可以直接呼叫啦...或许会有这样的需求?
B 也差不多

// ################################
//NewAModuleAPI return new AModuleAPI
func NewAModuleAPI() AModuleAPI {
	return &aModuleImpl{}
}

//AModuleAPI ...
type AModuleAPI interface {
	TestA() string
}

type aModuleImpl struct{}

func (*aModuleImpl) TestA() string {
	return "A module running"
}

<<:  Day 28 Heroku Docker

>>:  【DAY 29】Microsoft 365 X Dynamic 365该怎麽选才好呢? (下)

Day23 - ListView

上次学的Spinner需要点选下拉钮,才显示项目 而ListView则是直接把所有项目列出来 两者的...

Day6 - 变数的进阶操作

MAP() 从旧的变数 到新の变数 利用P5.js map 去做你的变数的调整 并且 map(val...

[Day 2] 一个非同步案例 httpServer

前言 或许有些人会有所困惑, 同步非同步的实践难在哪里, 为甚麽要一直巴拉巴拉, 但事实上, 非同步...

端点防护软件 - 弱点通报机制 VANS

可以这样点了又点,扫了还要扫吗 适用人员: 技术人员。 适用法规: 资通安全责任等级分级办法 - 附...

02 自学的契机

由於想要完整将自己从小至今的学习历程完整叙述,容我从小一开始接触程序的故事说起: 从记忆中对实作的印...