golang设计模式

一、状态模式

可以将枚举的类型(比如:停止和开始),将这两种状态封装为各自的对象,封装对象可以抽象独立。多个对象可以共享一个状态对象,从而将系统中的各个状态抽象化。

type State interface {
	doAction(context *Context)
	toString() string
}
// ==== 开始 ====
type StartState struct {}
func (this *StartState) doAction(context *Context) {
	fmt.Println("开始--- 这里可以做修改状态的逻辑操作")
	context.setState(this)
}
func (this *StartState) toString() string {
	return "Start State"
}
// ==== 停止 ====
type StopState struct {}
func (this *StopState) doAction(context *Context) {
	fmt.Println("结束--- 这里可以做修改状态的逻辑操作")
	context.setState(this)
}
func (this *StopState) toString() string {
	return "Stop State"
}
type Context struct {
	state State
}
func (this *Context) setState(state State) {
	this.state = state;
}
func (this *Context) getState() State {
	return this.state;
}
func Try() {
	context := &Context {
		state: nil,
	}

	// 修改当前状态
	start := &StartState{}
	start.doAction(context)
	fmt.Println(context.getState().toString())
	// 修改当前状态
	stop := &StopState{}
	stop.doAction(context)
	fmt.Println(context.getState().toString())
}
二、原型模式

适用场景:一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用

type User struct {
	name string
	age int
	sex int
}
type UserExt struct {
	synopsis string // 简介
}

type UserInfo struct {
	User
	UserExt
}
func (this *UserInfo) setUser(name string, age int, sex int) {
	this.name = name
	this.age = age
	this.sex = sex
}
func (this *UserExt) setUserExt(synopsis string) {
	this.synopsis = synopsis
}
func (this *UserInfo) display() {
	fmt.Println("个人信息:", this.name, this.age, "简介:", this.synopsis)
}

// ==== 这里是核心 ====
func (this *UserInfo) clone() *UserInfo {
	// 将UserInfo对象赋值给newUserInfo
	newUserInfo := *this
	// 这里就可以返回一个新的UserInfo对象
	return &newUserInfo
}
// ===================
func Try() {
	user1 := &UserInfo{}
	user1.setUser("张三", 90, 1)
	user1.setUserExt("这是张三简历简介")

	user2 := user1.clone()
	user2.setUser("李四", 19, 2)
	user2.setUserExt("这是李四简历简介")

	user3 := user1.clone()
	user3.setUser("赵六", 20, 1)
	user3.setUserExt("这是赵六简历简介")

	user1.display()
	user2.display()
	user3.display()
}
三、享元模式
数据库连接池
type User struct {
	name string
}
var mutex sync.Mutex
type UserFactory struct {
	userMap map[string]*User
}
func (this *UserFactory) showKeys() {
	for key := range this.userMap {
		fmt.Println(key)
	}
}
// 多线程可获取
func (this *UserFactory) getUser(name string) User {
	user, ok := this.userMap[name]
	// 此处防止多线程获取,会创建多个相同实例,使用双重锁,避免每次加锁
	if !ok {
		mutex.Lock()
		defer mutex.Unlock()
		if  _, ok = this.userMap[name]; !ok {
			user = &User{name: name}
			this.userMap[name] = user
		}
	}
	return *user
}
func Try() {
	userFactory := UserFactory{
		userMap: map[string]*User{},
	}
	fmt.Println(userFactory.getUser("张三"))
	fmt.Println(userFactory.getUser("张三"))
	fmt.Println(userFactory.getUser("张三"))

	fmt.Println(userFactory.getUser("李四"))
	fmt.Println(userFactory.getUser("赵六"))

	userFactory.showKeys()
}
四、组合模式

这种模式创建了一个包含自己对象组的类。该类提供了修改相同对象组的方式。
演示一个组织中员工的层次结构

type Employee struct {
	name string
	dept string
	salary int
	// 这个切片存储下属信息
	subordinates []*Employee
}
// 添加下属
func (this *Employee) addSubordinate(emp *Employee)  {
	this.subordinates = append(this.subordinates, emp)
}
func (this *Employee) showEmps() {
	for index, item := range this.subordinates {
		fmt.Println(index, item)
	}
}
func NewEmployee(name string, dept string, salary int) *Employee {
	return &Employee{
		name: name,
		dept: dept,
		salary: salary,
		subordinates: []*Employee{},
	}
}
func Try() {
	// 最大的CEO
	ceo := NewEmployee("jack", "CEO", 2000000)
	// 经理
	manger1 := NewEmployee("tom", "manager", 10000)
	manger2 := NewEmployee("jerry", "manager", 10000)
	manger3 := NewEmployee("less", "manager", 10000)
	manger4 := NewEmployee("bob", "manager", 10000)
	// ceo的下属是经理
	ceo.addSubordinate(manger1)
	ceo.addSubordinate(manger2)
	ceo.addSubordinate(manger3)
	ceo.addSubordinate(manger4)

	// 基础雇员
	emp1 := NewEmployee("deng1", "employee", 2000)
	emp2 := NewEmployee("deng2", "employee", 2000)
	emp3 := NewEmployee("deng3", "employee", 2000)
	emp4 := NewEmployee("deng4", "employee", 2000)
	emp5 := NewEmployee("deng5", "employee", 2000)
	emp6 := NewEmployee("deng6", "employee", 2000)
	emp7 := NewEmployee("deng7", "employee", 2000)

	// 给经理添加下属
	manger1.addSubordinate(emp1)
	manger1.addSubordinate(emp2)
	manger1.addSubordinate(emp3)
	manger2.addSubordinate(emp4)
	manger2.addSubordinate(emp5)
	manger3.addSubordinate(emp6)
	manger3.addSubordinate(emp7)

	ceo.showEmps()
}
五、代理模式

可以想象成:买火车票不一定在火车站买,也可以去代售点(就是代理处理某些事务的类)

// 先初始化总代理
var proxyLeader = &ProxyLeader{
	TicketNumber: 1000,
}

// 总代理
type ProxyLeader struct {
	TicketNumber int
}
func (this *ProxyLeader) BuyTicket() {
	this.TicketNumber--
}

// 分代理
type ProxyBranch struct {
	leader *ProxyLeader
	TicketNumber int
}
func (this *ProxyBranch) BuyTicket() {
	if this.leader == nil {
		this.leader = proxyLeader
		this.TicketNumber = this.leader.TicketNumber
	}
	// 代理只减去库存
	this.TicketNumber--
	// 购买的职责交给总代理
	this.leader.BuyTicket()
}
func Try() {
	branch := &ProxyBranch{ }
	branch.BuyTicket()

	// 输出代理库存
	fmt.Println(branch.TicketNumber)
	fmt.Println(branch.leader.TicketNumber)
}
六、适配器模式

形象的例子1:美国电器 110V,中国 220V,就要有一个适配器将 110V 转化为 220V
形象的例子2:音频播放器自带的支持mp3格式,此时需要对硬件升级,兼容适配mp4、vlc格式的,就需要对原本的播放器增加适配器兼容新的格式。

默认播放器

type MediaPlayer interface {
	play(fileName string)
}
type AudioPlayer struct {}
func (this *AudioPlayer) play(fileName string)  {
	fmt.Println("播放mp3格式,文件名称:", fileName)
}
func Try() {
	player := AudioPlayer{}
	player.play("测试1.mp3")
}

现在我们需要,支持mp4、vlc格式的音频,但是又不想重构,怎么办?

适配其他播放格式

// 高级媒体播放器
type AdvancedMediaPlayer interface {
	playVlc(fileName string)
	playMp4(fileName string)
}
// vlc格式播放器
type VlcPlayer struct {}
func (this *VlcPlayer) playVlc(fileName string)  {
	fmt.Println("播放vlc格式,文件名称:", fileName)
}
func (this *VlcPlayer) playMp4(fileName string) {
}
// mp4格式
type Mp4Player struct {}
func (this *Mp4Player) playVlc(fileName string)  {
}
func (this *Mp4Player) playMp4(fileName string) {
	fmt.Println("播放mp4格式,文件名称:", fileName)
}
type MediaAdapter struct {
	AdvancedMediaPlayer
}
func (this *MediaAdapter) play(fileName string) {
	if strings.HasSuffix(fileName, ".vlc") {
		this.playVlc(fileName)
	} else if strings.HasSuffix(fileName, ".mp4") {
		this.playMp4(fileName)
	}
}
// 根据文件后缀,返回对应结构体
func NewMediaAdapter(fileName string) *MediaAdapter  {
	adpter := &MediaAdapter{}
	if strings.HasSuffix(fileName, ".vlc") {
		adpter.AdvancedMediaPlayer = &VlcPlayer{}
	} else if strings.HasSuffix(fileName, ".mp4") {
		adpter.AdvancedMediaPlayer = &Mp4Player{}
	}
	return adpter
}
type MediaPlayer interface {
	play(fileName string)
}
type AudioPlayer struct {
	MediaPlayer
}
func (this *AudioPlayer) play(fileName string)  {
	if strings.HasSuffix(fileName, ".mp3") {
		// mp3 也可抽出为适配器,方便扩展,方便统一管理
		fmt.Println("播放mp3格式,文件名称:", fileName)
	} else if strings.HasSuffix(fileName, ".vlc") || strings.HasSuffix(fileName, ".mp4") {
		this.MediaPlayer = NewMediaAdapter(fileName)
		this.MediaPlayer.play(fileName)
	} else {
		fmt.Println("不支持改播放格式")
	}
}
七、观察者模式

观察者模式也是我们日常比较常接触到的设计模式之一。在一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。
常见:数据库修改一个模型的数据,与其关联的多张表也需要同步修改,这时就可以使用观察者模式进行广播,通知其他模型进行修改数据。


之前做android开发经常会接触到notify这类似的方法,这就是观察者模式实现,使用之前在全局注册一个监听,触发某个事件时会通知所有的监听对象进行修改。

type Project struct {
	id int
	name_cn string
	city_id int
	listeners []listener
}
// 修改City_id时通知所有观察者
func (this *Project) setCity(city_id int) {
	this.city_id = city_id
	// 通知观察者
	this.notifyAllProjectSync()
}
func (this *Project) notifyAllProjectSync()  {
	for _, listener := range this.listeners {
		listener.onListenerProjectUpdate()
	}
}
// 注册观察到监听类
func (this *Project) addListener(listener listener)  {
	this.listeners = append(this.listeners, listener)
}
// 监听接口
type listener interface {
	onListenerProjectUpdate()
}

// ==== 项目异步类 =====
type ProjectSync struct {
	region_leader_id int
	*Project
}
// 新建时注册到Project,监听Project修改
func NewProjectSync(project Project) {
	projectSync := &ProjectSync{region_leader_id: 0}
	project.addListener(projectSync)
}
// 注册监听Project修改,可以做处理一些相关类的触发修改机制
func (this *ProjectSync) onListenerProjectUpdate()  {
	if this.city_id == 1 {
		this.region_leader_id = 1
	} else {
		this.region_leader_id = 2
	}
	fmt.Println("ProjectSync触发,完成修改region_leader_id,当前值:",this.region_leader_id)
}

// ==== 资源异步类 ====
type ProjectNewsSync struct {
	region_leader_id int
	*Project
}
// 新建时注册到Project,监听Project修改
func NewProjectNewsSync(project Project) {
	projectNews := &ProjectNewsSync{region_leader_id: 0}
	project.addListener(projectNews)
}
// 注册监听Project修改,可以做处理一些相关类的触发修改机制
func (this *ProjectNewsSync) onListenerProjectUpdate()  {
	if this.city_id == 1 {
		this.region_leader_id = 1
	} else {
		this.region_leader_id = 2
	}
	fmt.Println("ProjectNewsSync触发,完成修改region_leader_id,当前值:",this.region_leader_id)
}
func Try(){
	project := &Project{}
	
	NewProjectNewsSync(project)
	NewProjectSync(project)

	// 修改城市为1,附属观察者触发监听
	project.setCity(1)
	// 修改城市为2,附属观察者触发监听
	project.setCity(2)
}