策略模式、代理模式、建造者模式、模板方法模式及其Go语言实现

1、策略模式

(1)什么是策略模式?
策略模式是指对象的某个行为在不同的场景中,拥有不同的实现策略。
策略模式属于行为型模式,策略模式的本质其实就是面向对象中多态的思想。
(2)生活场景实例
小明的班级决定为期中考试成绩优异的同学颁发奖品。奖品一共有钢笔、篮球、本子、手表四种,每位同学可以自己选择想要哪一种类型的奖品。
不使用策略模式(即不使用多态):

package main

type Student interface {
	selectThePen(*pen)
	selectTheBasketball(*basketball)
	selectTheNotebook(*notebook)
	selectTheWatch(*watch)
}

type student struct {
	name string
}
func (s *student) selectThePen(p *pen) {
	fmt.Println(s.name, "选择了奖品:", p.Name())
}
func (s *student) selectTheBasketball(b *basketball) {
	fmt.Println(s.name, "选择了奖品:", b.Name())
}
func (s *student) selectTheNotebook(n *notebook) {
	fmt.Println(s.name, "选择了奖品:", n.Name())
}
func (s *student) selectTheWatch(w *watch) {
	fmt.Println(s.name, "选择了奖品:", w.Name())
}

type pen struct {}
func (p *pen) Name() string {
	return "钢笔"
}
type basketball struct {}
func (b *basketball) Name() string {
	return "篮球"
}
type notebook struct {}
func (n *notebook) Name() string {
	return "本子"
}
type watch struct {}
func (w *watch) Name() string {
	return "手表"
}

func main() {
	xiaowang := &student {
		name : "小王"
	}
	xiaowang.selectThePen(&pen{})
	xiaohong := &student {
		name : "小红"
	}
	xiaohong.selectTheNotebook(&notebook{})
	xiaoming := &student {
		name : "小明"
	}
	xiaoming.selectTheBasketball(&basketball{})
}

策略模式实现(使用多态):

package main

type Student interface {
	selectThePrize(Prize)
}
type Prize interface {
	Name() string
}

type student struct {
	name string
}
func (s *student) selectThePrize(p Prize) {
	fmt.Println(s.name, "选择了奖品:", p.Name())
}

type pen struct {}
func (p *pen) Name() string {
	return "钢笔"
}
type basketball struct {}
func (b *basketball) Name() string {
	return "篮球"
}
type notebook struct {}
func (n *notebook) Name() string {
	return "本子"
}
type watch struct {}
func (w *watch) Name() string {
	return "手表"
}

func main() {
	xiaowang := &student {
		name : "小王"
	}
	xiaowang.selectThePrize(&pen{})
	xiaohong := &student {
		name : "小红"
	}
	xiaohong.selectThePrize(&notebook{})
	xiaoming := &student {
		name : "小明"
	}
	xiaoming.selectThePrize(&basketball{})
	xiaohua := &student {
		name : "小花"
	}
	xiaohua.selectThePrize(&watch{})
}

(3)etcd interval_tree中的应用

type Comparable interface {
	// Compare gives the result of a 3-way comparison
	// a.Compare(b) = 1 => a > b
	// a.Compare(b) = 0 => a == b
	// a.Compare(b) = -1 => a < b
	Compare(c Comparable) int
}

2、代理模式

(1)什么是代理模式?
代理模式为其他对象提供一种代理以控制对这个对象的访问。
代理模式属于结构型模式。在某些情况下,一个对象不适合或者不能直接引用另一个对象,代理模式引入一个代理对象,通过代理对象实现对原对象的引用。代理模式的使用场景非常广泛,包括权限控制、数据库连接等。
代理分为静态代理和动态代理。
(2)生活场景实例
在小明的班级,任课老师每天都会布置家庭作业,同学们写完后,第二天统一上交给老师。

package main
import "fmt"

type Student interface {
	HandleInHomework(*teacher)
}
type Teacher interface {
	CollectHomework(string)
}

type student struct {
	name string
}
func (s *student) HandleInHomework(t *teacher) {
	fmt.Println(s.name, "交作业给", t.name)
	t.CollectHomework(s.name)
}
type teacher struct {
	name string
}
func (t *teacher) CollectHomework(name string) {
	fmt.Println(t.name, "收到了", name, "的作业")
}

func main() {
	zhangsan := &student {
		name : "张三",
	}
	t := &teacher {
		name : "语文老师",
	}
	zhangsan.HandleInHomework(t)
}

语文老师同时教了5个班级,没记全每个班的人数和同学的名字,但是他需要知道每个班级哪些同学没交作业。于是语文老师在每个班级都选了一个语文课代表出来,由语文课代表统一收集班级作业,统计没交作业的学生名单。这里语文课代表就是代理。

package main
import "fmt"

type Student interface {
	HandleInHomework(*teacher)
}
type Teacher interface {
	CollectHomework(string)
}

type student struct {
	name string
}
func (s *student) HandleInHomework(a *assistant) {
	fmt.Println(s.name, "交作业给", a.name)
	a.CollectHomework(s.name)
}
type teacher struct {
	name string
}
func (t *teacher) CollectHomework(name string) {
	fmt.Println(t.name, "收到了", name, "的作业")
}
type assistant struct {
	name string
	t *teacher
}
func (a *assistant) CollectHomework(name string) {
	fmt.Println(a.name, "收到了", name, "的作业")
	fmt.Println(a.name, "统计谁交了作业")
	a.t.CollectHomework(name)
}

func main() {
	zhangsan := &student {
		name : "张三",
	}
	t := &teacher {
		name : "语文老师",
	}
	a := &assistant {
		name : "语文课代表",
		t : t,
	}
	zhangsan.HandleInHomework(a)
}

(3)代理模式的特点
1)代理类和被代理类具有相同的父类(实现了相同的接口)。
2)代理类保存了一个被代理类的引用。
3)代理类接受所有调用端的请求,并且这些请求最终都会返回给被代理类。
(4)动态代理

type Teacher interface {
	collectHomework(string)
}

定义了接口Teacher,不去定义实现类,运行时自动生成实现了collectHomework接口的一个实例。
(5)etcd auth中的应用

type AuthProxy struct {
	client *clientv3.Client
}

func (ap *AuthProxy) AuthEnable(ctx context.Context, r *pb.AuthEnableRequest)(*pb.AuthEnableResponse, error) {
	conn := ap.client.ActiveConnection()
	return pb.NewAuthClient(conn).AuthEnable(ctx, r)
}

3、建造者模式

(1)什么是建造者模式?
建造者模式是指将一个复杂对象的创建和它的表示分离,使得同样的构建过程可以创建不同的表示。
建造者模式是一种创建型模式,当一个对象的属性过于复杂时,我们可以把对象实例化的过程进行拆分成多个步骤,每个步骤负责初始化不同的属性。
(2)生活场景实例
新学期开学,小明的学校会进行分班,每个班级由班主任进行组建。班主任为了方便管理,为小明的班级选出若干班干部,包括班长、学习委员、语文课代表、数学课代表和英语课代表。

package main

import "fmt"

type class struct {
	monitor string
	studentAssistant string
	chineseAssistant string
	mathAssistant string
	englishAssistant string
}

func main() {
	c := &class {
		monitor : "小明",
		studentAssistant : "小红",
	}
	fmt.Printf("班长:%s,学习委员:%s", c.monitor, c.studentAssistant)
}

小明的班级班长竞选规则采取自主报名,由班级同学投票的方式进行选出。学习委员的竞选规则采取自主报名,由班主任指定担任。

package main

import "fmt"

type class struct {
	monitor string
	studentAssistant string
	chineseAssistant string
	mathAssistant string
	englishAssistant string
}
func (c *class) setMonitor(monitor string){
	fmt.Println("自主报名...")
	fmt.Println("班级同学投票...")
	fmt.Println("统计票数,得出结果...")
	c.monitor = monitor
}
func (c *class) setStudentAssistant(studentAssistant string){
	fmt.Println("自主报名...")
	fmt.Println("老师直接指定...")
	c.studentAssistant = studentAssistant
}

func main() {
	c := &class {}
	c.setMonitor("小明")
	c.setStudentAssistant("小红")
	fmt.Printf("班长:%s,学习委员:%s", c.monitor, c.studentAssistant)
}

当B班级也要进行选举时,用建造者模式代码如下:

package main

import "fmt"

type class interface{
	build() class
}
type classA struct {
	monitor string
	studentAssistant string
	chineseAssistant string
	mathAssistant string
	englishAssistant string
}
type classB struct {
	monitor string
	studentAssistant string
	chineseAssistant string
	mathAssistant string
	englishAssistant string
}

type ClassBuilder interface {
	buildMonitor(string) ClassBuilder
	buildStudentAssistant(string) ClassBuilder
	buildChineseAssistant(string) ClassBuilder
	buildMathAssistant(string) ClassBuilder
	buildEnglishAssistant(string) ClassBuilder
	build() class
}
func (c *classA) buildMonitor(monitor string) ClassBuilder {
	fmt.Println("自主报名...")
	fmt.Println("班级同学投票...")
	fmt.Println("统计票数,得出结果...")
	c.monitor = monitor
	return c
}
func (c *classB) buildMonitor(monitor string) ClassBuilder {
	fmt.Println("自主报名...")
	fmt.Println("任课老师和班主任共同指定...")
	c.monitor = monitor
	return c
}
func (c *classA) buildStudentAssistant(studentAssistant string) ClassBuilder {
	fmt.Println("自主报名...")
	fmt.Println("老师指定,得出结果...")
	c.studentAssistant = studentAssistant
	return c
}
func (c *classB) buildStudentAssistant(studentAssistant string) ClassBuilder {
	fmt.Println("自主报名...")
	fmt.Println("老师指定,得出结果...")
	c.studentAssistant = studentAssistant
	return c
}
func (c *classA) buildChineseAssistant(chineseAssistant string) ClassBuilder {
	c.chineseAssistant = chineseAssistant
	return c
}
func (c *classB) buildChineseAssistant(chineseAssistant string) ClassBuilder {
	c.chineseAssistant = chineseAssistant
	return c
}
func (c *classA) buildMathAssistant(mathAssistant string) ClassBuilder {
	c.mathAssistant = mathAssistant
	return c
}
func (c *classB) buildMathAssistant(mathAssistant string) ClassBuilder {
	c.mathAssistant = mathAssistant
	return c
}
func (c *classA) buildEnglishAssistant(englishAssistant string) ClassBuilder {
	c.englishAssistant = englishAssistant
	return c
}
func (c *classB) buildEnglishAssistant(englishAssistant string) ClassBuilder {
	c.englishAssistant = englishAssistant
	return c
}
func (c *classA) build() class {
	return c
}
func (c *classB) build() class {
	c.buildMonitor("小张").buildStudentAssistant("小吴")
	return c
}

func main() {
	c := &classA{}
	c.buildMonitor("小明").buildStudentAssistant("小红")
	fmt.Printf("A班级,班长:%s,学习委员:%s\n", c.monitor, c.studentAssistant)
	b := &classB{}
	b.build()
	fmt.Printf("B班级,班长:%s,学习委员:%s\n", b.monitor, b.studentAssistant)
}

(3)建造者模式的特点
1)属性的初始化过程互相独立,易扩展。
2)内部变化复杂的情况下会产生很多建造类。
(4)BeegoHTTPRequest中的应用

func (b *BeegoHTTPRequest) SetBasicAuth(username, password string) *BeegoHTTPRequest {
	b.req.SetBasicAuth(username, password)
	return b
}

// SetEnableCookie sets enable/disable cookiejar
func (b *BeegoHTTPRequest) SetEnableCookie(enable bool) *BeegoHTTPRequest {
	b.setting.EnableCookie = enable
	return b
}

// SetUserAgent sets User-Agent header field
func (b *BeegoHTTPRequest) SetUserAgent(useragent string) *BeegoHTTPRequest {
	b.setting.UserAgent = useragent
	return b
}

4、模板方法模式

(1)什么是模板方法模式?
模板方法模式定义一个算法的步骤,并允许子类为一个或多个步骤提供其具体实现。
模板方法模式属于行为型模式,其本质无非就是利用了里氏替换原则(所有使用父类的地方都可以用子类替代,子类可以扩展父类的功能,但不能改变父类的功能),也是面向对象多态思想的体现。
(2)生活场景实例
每周一到周五,小明都要去上学,小明上学的一天基本都是固定的,去学校、晨读、上课、下课、放学。今天是星期一,小明去学校上学了。

package main

import "fmt"

type Student interface {
	SchoolDay()
}
type student struct {
	name string
}
func (s *student) GoToSchool() {
	fmt.Println(s.name, "去学校")
}
func (s *student) MorningReading() {
	fmt.Println(s.name, "晨读")
}
func (s *student) TakingClasses() {
	fmt.Println(s.name, "上课")
}
func (s *student) ClassesOver() {
	fmt.Println(s.name, "下课")
}
func (s *student) SchoolOver() {
	fmt.Println(s.name, "放学")
}
func (s *student) SchoolDay() {
	s.GoToSchool()
	s.MorningReading()
	s.TakingClasses()
	s.ClassesOver()
	s.SchoolOver()
}

func main() {
	s := &student{
		name : "小明"
	}
	s.SchoolDay()
}

小张跟小明是同班同学,小张学习非常努力,上课期间除了学习学校的课程之外,还会用课余时间进行补习。

package main

import "fmt"

type Student interface {
	SchoolDay()
}
type xiaoming struct {
	template
	name string
}
type xiaozhang struct {
	template
	name string
}
func (xiaozhang *xiaozhang) TakingClasses() {		// 子类的方法覆盖模板父类的方法
	fmt.Println(xiaozhang.name, "上课")
	fmt.Println(xiaozhang.name, "补习")
}

type Template interface {
	GoToSchool()
	MorningReading()
	TakingClasses()
	ClassesOver()
	SchoolOver()
}
type template struct {
	name string
}
func (s *template) GoToSchool() {
	fmt.Println(s.name, "去学校")
}
func (s *template) MorningReading() {
	fmt.Println(s.name, "晨读")
}
func (s *template) TakingClasses() {
	fmt.Println(s.name, "上课")
}
func (s *template) ClassesOver() {
	fmt.Println(s.name, "下课")
}
func (s *template) SchoolOver() {
	fmt.Println(s.name, "放学")
}
func (s *template) SetName(name string){
	s.name = name
}

func SchoolDay(s Template) {
	s.GoToSchool()
	s.MorningReading()
	s.TakingClasses()
	s.ClassesOver()
	s.SchoolOver()
}

func main() {
	xiaoming := &xiaoming{
		name : "小明"
	}
	xiaoming.SetName(xiaoming.name)
	SchoolDay(xiaoming)
	xiaozhang := &xiaozhang{
		name : "小张"
	}
	xiaozhang.SetName(xiaozhang.name)
	SchoolDay(xiaozhang)
}

(3)模板方法的特点
1)提高了代码的复用性。
2)提高了拓展性。
3)缺点:每一种算法的实现都需要新增一个子类,导致了子类个数的增加,增加了系统实现的复杂度。
(4)go-micro service中的应用

type Service interface{
	Init(...Option)
	Option() Options
	Client() client.Client
	Server() server.Server
	Run() error
	String() string
}

// Function is a one time executing Service
type Function interface {
	// Inherits Service interface
	Service
	// Done signals to complete execution
	Done() error
	// Handle registers an RPC handler
	Handle(v interface{}) error
	// Subscribe registers a subscriber
	Subscribe(topic string, v interface{}) error
}

(5)go http包中的应用

// Handle registers the handler for the given pattern in the DefaultServeMux.
// The documentation for ServeMux explains how patterns are matched.
func Handle(pattern string, handler Handler) {
	DefaultServeMux.Handle(pattern, handler)
}

// HandleFunc registers the handler function for the given pattern in the DefaultServeMux.
// The documentation for ServeMux explains how patterns are matched.
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
	DefaultServeMux.HandleFunc(pattern, handler)
}
发布了238 篇原创文章 · 获赞 617 · 访问量 132万+

猜你喜欢

转载自blog.csdn.net/gongxifacai_believe/article/details/104243923
今日推荐