# 设计模式

# 工厂模式

工厂模式(Factory Pattern)是软件设计中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。在每增加一种类型时,只需要修改工厂函数即可。 在产品较多时,工厂函数代码逻辑将会非常复杂。

type Restaurant interface {
	GetFood()
}

type ChuanChuan struct {}

func (d *ChuanChuan) GetFood() {
	fmt.Println("串串的饭菜已经做好")
}

type Qingfeng struct {}

func (q *Qingfeng) GetFood() {
	fmt.Println("庆风包子铺已经做好")
}

func NewRestaurant(name string)  Restaurant {
	switch name {
	case "d":
		return &ChuanChuan{}
	case "q":
		return &Qingfeng{}
	}
	return nil
}

func main() {
	// 工厂模式:首先要规定你生成的商品的功能是什么,如上的Restaurant接口就是要求商品都能获得食物
	// 然后我们分别写能完成接口功能的结构体,然后通过NewRestaurant方法的select来通过不同的传参生产不同的商品
	NewRestaurant("d").GetFood()
	NewRestaurant("q").GetFood()
}

# 抽象工厂模式

抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。 使用抽象工厂模式一般要满足以下条件。

  • 系统中有多个产品族,每个具体工厂创建同一族但属于不同等级结构的产品。
  • 系统一次只可能消费其中某一族产品,即同族的产品一起使用。

抽象工厂模式除了具有工厂方法模式的优点外,其他主要优点如下。

  • 可以在类的内部对产品族中相关联的多等级产品共同管理,而不必专门引入多个新的类来进行管理。
  • 当增加一个新的产品族时不需要修改原代码,满足开闭原则
package main

import (
	"fmt"
)

// lunch是表示一个具有cook功能的商品,下面的rise米饭和tomato番茄都实现了可以cook
type Lunch interface {
	Cook()
}

type  Rise struct {}

func (r *Rise)  Cook() {
	fmt.Println("it's rise")
}

type Tomato struct {}

func (t *Tomato) Cook() {
	fmt.Println("it's Tomato")
}

type SimpleLunchFactory struct {}

// lunchFactory接口是表示具有createFood和Createvegetable功能的
type LunchFactory interface {
	// 抽象工厂在此体现:接口内的方法会返回一个接口,这使得实现了LunchFactory的类与实现了Lunch功能的类进行绑定
	CreateFood() Lunch
	CreateVegetable() Lunch
}

func NewSimpleLunchFactory() LunchFactory {
	return &SimpleLunchFactory{}
}

func (c *SimpleLunchFactory) CreateFood() Lunch {
	return &Rise{}
}

func (c *SimpleLunchFactory) CreateVegetable() Lunch {
	return &Tomato{}
}

func main() {
	factory := NewSimpleLunchFactory()
	food:= factory.CreateFood()  // 通过LunchFactory的接口的方法来具体的创建不同的类
	food.Cook()

	vegetable := factory.CreateVegetable()
	vegetable.Cook()
}

# 建造者模式

建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

一个 Builder 类会一步一步构造最终的对象。该 Builder 类是独立于其他对象的。

import (
	"bytes"
	"fmt"
)


// builder设计模式,主要解决多变参数传递问题
// xorm就是使用了builder设计模式
// 故事: 平时去面馆吃面,有各种味道的面条(牛肉味、肥肠味等)
// 有各种配料(香菜、葱、姜、辣椒等)
// 第一个客人:一碗牛肉面 加葱、姜
// 第二个客人:一碗牛肉面 加葱、香菜

// 相当于面的材料
type MyBuilder struct {
	NoodlesType string // 面条口味
	Coriander   bool   // 是否加香菜
	Onion       bool   // 是否加葱
	Ginger      bool   // 是否加姜
	Pepper      bool   // 是否加辣椒
}

// 构造一个结构体
func NewMyBuilder(noodsType string) MyBuilder {
	return MyBuilder{NoodlesType: noodsType}
}

// 加香菜
func (myBuilder MyBuilder) withCoriander() MyBuilder {
	myBuilder.Coriander = true
	return myBuilder
}

// 加葱
func (myBuilder MyBuilder) withOnion() MyBuilder {
	myBuilder.Onion = true
	return myBuilder
}

// 加姜
func (myBuilder MyBuilder) withGinger() MyBuilder {
	myBuilder.Ginger = true
	return myBuilder
}


// 加辣椒
func (myBuilder MyBuilder) withPepper() MyBuilder {
	myBuilder.Pepper = true
	return myBuilder
}

func (myBuilder MyBuilder) String() string {
	var buffer bytes.Buffer
	buffer.WriteString("要一碗" + myBuilder.NoodlesType + "面,")
	if myBuilder.Coriander {
		buffer.WriteString("加香菜、")
	} else {
		buffer.WriteString("不加香菜、")
	}


	if myBuilder.Onion {
		buffer.WriteString("加葱、")
	} else {
		buffer.WriteString("不加葱、")
	}


	if myBuilder.Ginger {
		buffer.WriteString("加姜、")
	} else {
		buffer.WriteString("不加姜、")
	}


	if myBuilder.Pepper {
		buffer.WriteString("加辣椒、")
	} else {
		buffer.WriteString("不加辣椒、")
	}
	buffer.WriteString("\n")
	return buffer.String()
}

func main() {
	myBuilder := NewMyBuilder("牛肉").
		withCoriander().
		withGinger()
	str := myBuilder.String()
	fmt.Println(str)
}
// 要一碗牛肉面,加香菜、不加葱、加姜、不加辣椒、

# 单例模式

单例模式(Singleton Pattern)是软件设计中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

package main

import (
	"fmt"
	"sync"
)

type Instance struct {
	Name    string
	Counter int //详细参数
}

// 1、懒汉模式:非线程安全。,有线程来访问此时LazyInstance = nil就会再创建,单例类就会有多个实例了。当正在创建时
var LazyInstance *Instance

func GetLazyInstance() *Instance {
	if LazyInstance == nil {
		LazyInstance = &Instance{
			Counter: 0,
			Name:    "LazyInstance",
		}
	}
	return LazyInstance
}

// 改进型懒汉模式
var mu sync.Mutex
var LazyInsPlusPlus *Instance

func GetLazyInsPlusPlus() *Instance {
	if LazyInsPlusPlus == nil {
		mu.Lock()
		defer mu.Unlock()
		LazyInsPlusPlus = &Instance{
			Counter: 0,
			Name:    "LazyInsPlusPlus",
		}
	}
	return LazyInsPlusPlus
}

// sync.once实现
var once sync.Once
var SyncOnceInstance *Instance

func GetInstanceSyncOnce() *Instance {
	once.Do(func() {
		SyncOnceInstance = &Instance{
			Counter: 0,
			Name:    "SyncOnceInstance",
		}
	})
	return SyncOnceInstance
}

func (i *Instance) Hello() {
	fmt.Printf("%s: my current counter is:%d\n", i.Name, i.Counter)
}

//省略实现
func main() {
	//懒汉模式测试
	ls := GetLazyInstance()
	ls.Hello()
	ls.Counter += 1
	ls1 := GetLazyInstance()
	ls1.Hello()

	//饿汉模式测试
	lspp := GetLazyInsPlusPlus()
	lspp.Hello()
	lspp.Counter += 1000
	lspp1 := GetLazyInsPlusPlus()
	lspp1.Hello()

	//sync once 测试
	sc := GetInstanceSyncOnce()
	sc.Hello()
	sc.Counter += 10000
	sc1 := GetInstanceSyncOnce()
	sc1.Hello()
}

/*
LazyInstance: my current counter is:0
LazyInstance: my current counter is:1
LazyInsPlusPlus: my current counter is:0
LazyInsPlusPlus: my current counter is:1000
SyncOnceInstance: my current counter is:0
SyncOnceInstance: my current counter is:10000
*/

# 创建型模式

# 原型模式

原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

type Cloneable interface {
	Clone() Cloneable
}

type Person struct {
	Name string
	Age int
	Height int
}

func (p *Person) Clone() *Person {
	person := *p
	return &person
}

func(p *Person) SetName(name string) {
	p.Name = name
}

func(p *Person) SetAge(age int) {
	p.Age = age
}

func main() {
	p := &Person{
		Name: "zhang san",
		Age: 20,
		Height: 175,
	}

	p1 :=p.Clone()
	p1.SetAge(30)
	p1.SetName("Li Si")

	fmt.Println("name:", p1.Name)
	fmt.Println("age:", p1.Age)
	fmt.Println("height:", p1.Height)
}
/*
name: Li Si
age: 30
height: 175
*/

# 适配器模式

适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。这种模式涉及到一个单一的类,该类负责加入独立的或不兼容的接口功能。例如: 在现实生活中,我们的笔记本电脑的工作电压大多数都是20V,而我国的家庭用电是220V,如何让20V的笔记本电脑能够工作在220V的电压下工作?答案:引入一个电源适配器,俗称变压器,有了这个电源适配器,生活用电和笔记本电脑即可兼容。

// 将一个类的接口转换成客户希望的另一个接口,Adapter模式使得原本由于接口
// 不兼容而不能一起工作的那些类可以一起工作
// 定义一个新的接口
type Target interface {
	Process()
}

// 定义一个老的接口
type Adaptee interface {
	Foo()
	Bar()
}

// 定一个Adapter接口
type Adapter struct {
	adaptee Adaptee
}

func (a *Adapter) Process(){
	fmt.Println("在Adapter中执行process()")  // 在之前的基础上执行原有process函数
	a.adaptee.Bar()
	a.adaptee.Foo()
}

// 实现旧接口struct
type oldAdaptee struct {}

func (o *oldAdaptee) Foo(){
	fmt.Println("在旧接口中执行foo()")
}

func (o *oldAdaptee) Bar(){
	fmt.Println("在旧的接口中执行bar()")
}

func main(){
	oa := new(oldAdaptee)
	// 定一个适配器对象
	adapter := new(Adapter)
	adapter.adaptee = oa
	adapter.Process()
}

# 结构设计模式

# 代理模式

代理设计模式是一种结构设计模式。这种模式建议为控制和访问主要对象提供额外的间接层。

在这种模式下,将创建一个新的代理类,该类实现与主对象相同的接口。这使您可以在主对象的实际逻辑之前或者之后执行某些行为。

package main

import "fmt"

type server interface {
	handleRequest(string, string) (int, string)
}

type nginx struct {
	application       *application
	maxAllowedRequest int
	rateLimiter       map[string]int
}

func newNginxServer() *nginx {
	return &nginx{
		application:       &application{},
		maxAllowedRequest: 2,
		rateLimiter:       make(map[string]int),
	}
}

func (n *nginx) handleRequest(url, method string) (int, string) {
	allowed := n.checkRateLimiting(url)
	if !allowed {
		return 403, "Not Allowed"
	}
	return n.application.handleRequest(url, method)
}

func (n *nginx) checkRateLimiting(url string) bool {
	if n.rateLimiter[url] == 0 {
		n.rateLimiter[url] = 1
	}
	if n.rateLimiter[url] > n.maxAllowedRequest {
		return false
	}
	n.rateLimiter[url] = n.rateLimiter[url] + 1
	return true
}

type application struct {
}

func (a *application) handleRequest(url, method string) (int, string) {
	if url == "/app/status" && method == "GET" {
		return 200, "Ok"
	}
	if url == "/create/user" && method == "POST" {
		return 201, "User Created"
	}
	return 404, "Not Ok"
}

func main() {
	nginxServer := newNginxServer()
	appStatusURL := "/app/status"
	createuserURL := "/create/user"
	httpCode, body := nginxServer.handleRequest(appStatusURL, "GET")
	fmt.Printf("\nUrl: %s\nHttpCode: %d\nBody: %s\n", appStatusURL, httpCode, body)
	httpCode, body = nginxServer.handleRequest(appStatusURL, "GET")
	fmt.Printf("\nUrl: %s\nHttpCode: %d\nBody: %s\n", appStatusURL, httpCode, body)
	httpCode, body = nginxServer.handleRequest(appStatusURL, "GET")
	fmt.Printf("\nUrl: %s\nHttpCode: %d\nBody: %s\n", appStatusURL, httpCode, body)
	httpCode, body = nginxServer.handleRequest(createuserURL, "POST")
	fmt.Printf("\nUrl: %s\nHttpCode: %d\nBody: %s\n", createuserURL, httpCode, body)
	httpCode, body = nginxServer.handleRequest(createuserURL, "GET")
	fmt.Printf("\nUrl: %s\nHttpCode: %d\nBody: %s\n", createuserURL, httpCode, body)
}

/*
Url: /app/status
HttpCode: 200
Body: Ok

Url: /app/status
HttpCode: 200
Body: Ok

Url: /app/status
HttpCode: 403
Body: Not Allowed

Url: /create/user
HttpCode: 201
Body: User Created

Url: /create/user
HttpCode: 404
Body: Not Ok
*/