适配器模式、单例模式、工厂模式及其Go语言实现

1、适配器模式

(1)什么是适配器模式?
适配器模式作为两个不兼容的接口之间的桥梁,将一个接口转换为我们希望的另一个接口。
适配器模式其实是一种结构型模式,我们读源码过程中接触到的Adapter、Wrapper基本都是适配器模式的实现。
适配器分为两类:类适配器(采用多继承方式)和对象适配器(采用组合方式)。
适配器模式的角色:Target(目标接口)、Adaptee(被适配的对象)、Adaptor(适配器)。
(2)生活场景实例
小明的书包一般是有夹层的,书籍放到书包里,考试试卷放到书包夹层里。小明的妈妈给小明在淘宝上买了一个书包,小明发现这个书包没有夹层。

package main

import "fmt"

type Backpack interface {
	putTheBook([]string)
}
type backpack struct {

}

func (bp *backpack) putTheBook(books []string) {
	for _, book := range books {
		fmt.Println("把%s放入书包里面\n", book)
	}
}

type TargetBackpack interface {
	putTheBook([]string, []string)
}
type targetBackpack struct {

}

func (tb *targetBackpack) putTheBook(books []string, papers []string){
	for _, book := range books {
		fmt.Println("把%s放入书包里面\n", book)
	}
	for _, paper := range papers {
		fmt.Println("把%s放入书包夹层里面\n", paper)
	}
}

func main() {
	books := []string{"语文书", "数学书", "英语书"}
	papers := []string{"语文试卷", "数学试卷"}

	bp := &backpack{}
	tb := &targetBackpack{}
	bp.putTheBook(books)
	fmt.Println("=======================")
	tb.putTheBook(books, papers)

小明的妈妈于是想了个办法,找了一块和书包同材质的布料,然后手工做了一个夹层,使这个书包变成了夹层书包。这里的角色分为:Target(有夹层的书包)、Adaptee(普通书包)、Adapter(夹层)。

package main

import "fmt"

type Backpack interface {
	putTheBook([]string)
}
type backpack struct {}
func (bp *backpack) putTheBook(books []string) {
	for _, book := range books {
		fmt.Println("把%s放入书包里面\n", book)
	}
}

type Adapter interface {
	putTheBook([]string, []string)
}
type adapter struct {
	bp backpack
}
func (ad *adapter) putTheBook(books []string, papers []string) {
	ad.bp.putTheBook(books)
	for _, paper := range papers {
		fmt.Println("把%s放入书包夹层里面\n", paper)
	}
}

func main() {
	books := []string{"语文书", "数学书", "英语书"}
	papers := []string{"语文试卷", "数学试卷"}

	bp := &backpack{}
	ad := &adapter{}
	bp.putTheBook(books)
	fmt.Println("=======================")
	ad.putTheBook(books, papers)
}

(3)适配器模式和装饰者模式的区别
1)适配器模式Adaptee和Target的接口形式不同,而装饰者模式的装饰者和被装饰者的接口形式相同,即接口下的方法的名字和参数列表相同。
2)Adapter保存了Adaptee的引用,接收调用端的请求,并且这些请求最终都会调用Adaptee的接口。
(4)grpc中的应用

func (d *dnsResolver) lookupSRV() []resolver.Address {
	var newAddrs []resolver.Address
	_, srvs, err := d.resolver.LookupSRV(d.ctx, "grpclb", "tcp", d.host)
	if err != nil {
		grpclog.Infof("grpc: failed dns SRV record lookup due to %v.\n", err)
		return nil
	}
	...
	return newAddrs
}

2、单例模式

(1)什么是单例模式?
单例模式保证一个类仅有一个实例,并提供一个访问它的全局访问点。
单例模式是最简单的设计模式之一,属于创建型模式。单例模式被广泛运用在资源共享的场景,避免对象的频繁创建和回收。比如日志打印、数据库连接池等。
单例模式的实现方式:私有化构造方法。
(2)生活场景实例
小明的班级为了方便管理,老师指定了小明为班长。同学们有任何需要帮助的地方先告诉班长,班长解决不了再汇报给老师。

package main

import "fmt"

type Monitor interface {
	Help(string)
}
type Member interface {
	AskForHelp(string)
}

type monitor struct{
	name string
}
func (mo *monitor) Help(name string) {
	fmt.Println("%s帮助了%s", mo.name, name)
}
type member struct {
	name string
}
func (mem *member) AskForHelp(name string) {
	mo := &monitor{
		name : name,
	}
	fmt.Println("%s寻求了%s的帮助", mem.name, name)
	mo.Help(mem.name)
}

这一天,张三在学业上碰到了困难,于是找班长小明寻求帮助。

func main() {
	zhangsan := &member{
		name : "张三",
	}
	zhangsan.AskForHelp("小明")
}

同时,李四和王五因为闹矛盾,也来找班长小明评理。

func main() {
	zhangsan := &member{
		name : "张三",
	}
	zhangsan.AskForHelp("小明")
	lisi := &member{
		name : "李四",
	}
	lisi.AskForHelp("小明")
	wangwu := &member {
		name : "王五",
	}
	wangwu.AskForHelp("小明")
}

在以上代码中,班长小明被实例化了多次,如果班级有许多同学,每个同学来寻求小明的帮助,就会在内存中产生很多的小对象。解决方式:

package main

import "fmt"

type Monitor interface {
	Help(string)
}
type Member interface {
	AskForHelp(string)
}

type monitor struct{
	name string
}
func (mo *monitor) Help(name string) {
	fmt.Println("%s帮助了%s", mo.name, name)
}
type member struct {
	name string
}
func (mem *member) AskForHelp(name string) {
	mo = GetMonitor(name)
	fmt.Println("%s寻求了%s的帮助", mem.name, name)
	mo.Help(mem.name)
}

var mo *monitor
func GetMonitor(name string) *monitor{
	if mo != nil {
		return mo
	}
	mo = &monitor {
		name : name,
	}
	return mo
}

func main() {
	zhangsan := &member{
		name : "张三",
	}
	zhangsan.AskForHelp("小明")
	lisi := &member{
		name : "李四",
	}
	lisi.AskForHelp("小明")
	wangwu := &member {
		name : "王五",
	}
	wangwu.AskForHelp("小明")
}

(3)线程安全
方式一:静态加载

var mo = &monitor {
	name : "小明"
}
var mu sync.Mutex
func GetMonitor(name string) *monitor{
	if mo != nil {
		return mo
	}
	return mo
}

方式二:加锁

var mo *monitor
var mu sync.Mutex
func GetMonitor(name string) *monitor{
	mu.Lock()					// 加锁
	defer mu.Unlock()			// 在return语句之前一定会执行该方法
	
	if mo != nil {
		return mo
	}
	mo = &monitor {
		name : name,
	}
	return mo
}

方式三:双重校验

var mo *monitor
var mu sync.Mutex
func GetMonitor(name string) *monitor{
	if mo != nil {
		return mo
	}
	mu.Lock()
	defer mu.Unlock()
	if mo != nil {					// 双重校验
		return mo
	}
	mo = &monitor {
		name : name,
	}
	return mo
}

方式四:once.Do

var mo *monitor
var once sync.Once
func GetMonitor(name string) *monitor{
	once.Do(func() {
		mo = &monitor{
			name : name,
		}
	})
	return mo
}

main函数:

import (
	"fmt"
	"log"
	"sync"
)

func main() {
	var wg sync.WaitGroup
	wg.Add(3)

	go func() {
		zhangsan := &member {
			name : "张三",
		}
		zhangsan.AskForHelp("小红")
		defer wg.Done()
	}()
	go func() {
		lisi := &member {
			name : "李四",
		}
		lisi.AskForHelp("小明")
		defer wg.Done()
	}()
	go func() {
		wangwu := &member {
			name : "王五",
		}
		wangwu.AskForHelp("小王")
		defer wg.Done()
	}()
	
	wg.Wait()
	log.Println("singleton")
}

(4)go log中的应用

var std = New(os.Stderr, "", LstdFlags)
func New(out io.Writer, prefix string, flag int) *Logger {
	return &Logger{out: out, prefix: prefix, flag: flag}
}
func Println(v ...interface{}) {
	std.Output(2, fmt.Sprintln(v...))
}

3、工厂模式

(1)什么是工厂模式?
工厂模式定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。
工厂模式属于创建型模式,工厂模式的初衷就是为了在创建对象时不会对调用方暴露创建逻辑。
工厂模式分为简单工厂模式、工厂方法模式和抽象工厂模式。
工厂模式是一种从简单到抽象的过程。
(2)生活场景实例
在小明的学校,每一年开学都会发教材,主要包括语文书、数学书、英语书,还有各种练习试卷。这一天,小明去领了三本教材,分别是语文书、数学书和英语书,老师忙不过来,指定某个同学去发书,同学们都去这个同学这里去领书。这个同学就是工厂。

package main
import "fmt"

type Book interface {
	Name() string
}

type chineseBook struct {
	name string
}
func (c *chineseBook) Name() string {
	return c.name
}
type mathBook struct {
	name string
}
func (m *mathBook) Name() string {
	return c.name
}
type englishBook struct {
	name string
}
func (e *englishBook) Name() string {
	return c.name
}

type Person interface {
	GetBook(string) Book
}
type person struct {}
func (p *person) GetBook(name string) Book {
	if name == "语文书" {
		return &chineseBook{
			name : name,
		}
	}
	if name == "数学书" {
		return &mathBook{
			name : name,
		}
	}
	if name == "英语书" {
		return &englishBook{
			name : name,
		}
	}
	return nil
}

func main() {
	// 不用工厂模式的写法
	c := &chineseBook {
		name : "语文书",
	}
	fmt.Println("小明领取了一本%s", c.Name())
	m := &mathBook {
		name : "数学书"
	}
	fmt.Println("小明领取了一本%s", m.Name())
	e := &englishBook {
		name : "英语书"
	}
	fmt.Println("小明领取了一本%s", e.Name())

	// 简单工厂模式的写法
	p := &person{}
	fmt.Println("小明领取了一本%s", p.GetBook("语文书").Name())
	fmt.Println("小明领取了一本%s", p.GetBook("数学书").Name())
	fmt.Println("小明领取了一本%s", p.GetBook("英语书").Name())
}

老师分别指定语文、数学、英语课代表,由课代表去发书。

package main
import "fmt"

type Book interface {
	Name() string
}

type chineseBook struct {
	name string
}
func (c *chineseBook) Name() string {
	return c.name
}
type mathBook struct {
	name string
}
func (m *mathBook) Name() string {
	return c.name
}
type englishBook struct {
	name string
}
func (e *englishBook) Name() string {
	return c.name
}

type Person interface {
	GetBook(string) Book
}
type chineseAssistant struct {}
func (c *chineseAssistant) GetBook(name string) Book {
	if name == "语文书" {
		return &chineseBook{
			name : name,
		}
	}
	return nil
}
type mathAssistant struct {}
func (m *mathAssistant) GetBook(name string) Book {
	if name == "数学书" {
		return &mathBook{
			name : name,
		}
	}
	return nil
}
type englishAssistant struct {}
func (e *englishAssistant) GetBook(name string) Book {
	if name == "英语书" {
		return &englishBook{
			name : name,
		}
	}
	return nil
}

func main() {
	// 工厂方法模式的写法:将大工厂实例化为子工厂
	c := &chineseAssistant{}
	fmt.Println("小明领取了一本%s", c.GetBook("语文书").Name())
	m := &mathAssistant{}
	fmt.Println("小明领取了一本%s", m.GetBook("数学书").Name())
	e := &englishAssistant{}
	fmt.Println("小明领取了一本%s", e.GetBook("英语书").Name())
}

每个学生除了领教材,还要领试卷。

package main
import "fmt"

type Book interface {
	Name() string
}
type Paper interface {
	Name() string
}

type chineseBook struct {
	name string
}
func (c *chineseBook) Name() string {
	return c.name
}
type chinesePaper struct {
	name string
}
func (c *chinesePaper) Name() string {
	return c.name
}
type mathBook struct {
	name string
}
func (m *mathBook) Name() string {
	return c.name
}
type mathPaper struct {
	name string
}
func (m *mathPaper) Name() string {
	return m.name
}
type englishBook struct {
	name string
}
func (e *englishBook) Name() string {
	return c.name
}
type englishPaper struct {
	name string
}
func (e *englishPaper) Name() string {
	return e.name
}

type Person interface {
	GetBook(string) Book
	GetPaper(string) Paper
}
type chineseAssistant struct {}
func (c *chineseAssistant) GetBook(name string) Book {
	if name == "语文书" {
		return &chineseBook{
			name : name,
		}
	}
	return nil
}
func (c *chineseAssistant) GetPaper(name string) Paper {
	if name == "语文试卷" {
		return &chinesePaper{
			name : name,
		}
	}
}
type mathAssistant struct {}
func (m *mathAssistant) GetBook(name string) Book {
	if name == "数学书" {
		return &mathBook{
			name : name,
		}
	}
	return nil
}
func (m *mathAssistant) GetPaper(name string) Paper {
	if name == "数学试卷" {
		return &mathPaper{
			name : name,
		}
	}
}
type englishAssistant struct {}
func (e *englishAssistant) GetBook(name string) Book {
	if name == "英语书" {
		return &englishBook{
			name : name,
		}
	}
	return nil
}
func (e *englishAssistant) GetPaper(name string) Paper {
	if name == "英语试卷" {
		return &englishPaper{
			name : name,
		}
	}
}

func main() {
	// 抽象工厂模式的写法:将大工厂实例化为子工厂,有更多的抽象方法
	c := &chineseAssistant{}
	fmt.Println("小明领取了一本%s", c.GetBook("语文书").Name())
	fmt.Println("小明领取了一张%s", c.GetBook("语文试卷").Name())
	m := &mathAssistant{}
	fmt.Println("小明领取了一本%s", m.GetBook("数学书").Name())
	fmt.Println("小明领取了一张%s", m.GetBook("数学试卷").Name())
	e := &englishAssistant{}
	fmt.Println("小明领取了一本%s", e.GetBook("英语书").Name())
	fmt.Println("小明领取了一张%s", e.GetBook("英语试卷").Name())
}

(3)简单工厂模式和抽象工厂模式的区别
简单工厂:直接提供工厂对象,创建产品实例。
抽象工厂:提供一系列创建产品实例的接口定义,具体怎么创建由子工厂实现。
(4)go CollatorFactory中的应用

func getCollator(name, locale string) Collator {
	for _, f := range collators{
		if f.name == name {
			col, err := f.makeFn(locale)
			if err != nil {
				log.Fatal(err)
			}
			return col
		}
	}
	log.Fatalf("collator of type %q not found", name)
	return nil
}
发布了238 篇原创文章 · 获赞 617 · 访问量 132万+

猜你喜欢

转载自blog.csdn.net/gongxifacai_believe/article/details/104236530