结构型模式主要关注如何将类或者对象组合成更大的结构,以便在不改变原有类或者对象的情况下,实现新的功能或者优化结构。
结构型模式核心思想是通过组合(Composition)而不是继承(Inheritance)来实现代码的复用和扩展
代理,桥接,组合,装饰器,适配器,外观,享元,七种模式。
结构型模式-代理模式 代理模式:通过代理对象来控制另一个对象,核心是不改变原对象的情况下,通过代理对象来增强或者限制对原对象的访问。
常见场景:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package  structural_patternimport  "fmt" type  Log struct  {} func  (Log)   Info(content string ) {	fmt.Println(content) } type  ProxyLog struct  {	log *Log } func  (p *ProxyLog)   Info(content string ) {	 	if  p.log == nil  { 		p.log = &Log{} 	} 	 	p.log.Info(content) 	 } 
 
1 2 3 4 5 6 7 8 package  structural_patternimport  "testing" func  TestProxyLog_Info (t *testing.T)   {	pl := ProxyLog{} 	pl.Info("hello world" ) } 
 
结构型模式-桥接模式 核心思想是将抽象部分和实现部分分离,是他们可以独立变化。避免类的数量爆炸,提高可扩展可维护性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 package  bridgeimport  "fmt" type  Computer interface  {	Print(file string )   	SetPrinter(Printer)  } type  Printer interface  {	PrintFile(file string )  } type  Epson struct {}func  (Epson)   PrintFile(file string ) {	fmt.Println("使用爱普生打印机打印文件" , file) } type  Hp struct {}func  (hp Hp)   PrintFile(file string ) {	fmt.Println("使用惠普打印机打印文件" , file) } type  Mac struct  {	printer Printer } func  (m *Mac)   Print(file string ) {	 	m.printer.PrintFile("mac:"  + file) } func  (m *Mac)   SetPrinter(p Printer) {	m.printer = p } type  Windows struct  {	printer Printer } func  (ws *Windows)   Print(file string ) {	ws.printer.PrintFile("windows:"  + file) } func  (ws *Windows)   SetPrinter(p Printer) {	ws.printer = p } 
 
1 2 3 4 5 6 7 8 9 10 11 12 package  bridgeimport  "testing" func  TestBridge (t *testing.T)   {	w := Windows{} 	hp := Hp{} 	w.SetPrinter(hp) 	w.Print("xxx" ) } 
 
结构型模式-组合模式 将对象组合成树形层次关系,  “部分-整体”,  组合模式让客户端可以统一的处理单个对象和对象的组合。
应用场景:
文件系统:文件,文件夹,文档树 
组织结构:部门员工关系 
 
为什么使用组合模式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package  compositeimport  "fmt" type  Node interface  {	Display(ident string ) } type  File struct  {	Name string  } type  Dir struct  {	Name     string  	Children []Node } func  (f File)   Display(ident string ) {	fmt.Println(ident + f.Name) } func  (d Dir)   Display(ident string ) {	fmt.Println(ident + d.Name) 	for  _, child := range  d.Children { 		child.Display(ident + "  " ) 	} } 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package  compositeimport  "testing" func  TestComposite (t *testing.T)   {	root := Dir{ 		Name: "CreateProjects" , 		Children: []Node{ 			Dir{ 				Name: "cmd" , 				Children: []Node{ 					File{ 						Name: "main.go" , 					}, 				}, 			}, 			File{ 				Name: "go.mod" , 			}, 		}, 	} 	root.Display("" ) } 
 
结构型模式-装饰器模式 动态的为对象添加行为和职责,不需要修改原始类。或者引入装饰者类, 运行时灵活的组合不通功能,而不需要创建大量子类。
装饰者的核心是为对象包装在一个或多个装饰者中,每个装饰者可以在调用被装饰方法前后添加额为的行为。
例如:
很像代理模式,代理模式除了增强还可以限制,  装饰器模式一般增强
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 package  decoratorimport  (	"fmt"  	"time"  ) type  ReqI interface  {	Handler(url string ) string  } type  Req struct  {} func  (r Req)   Handler(url string ) string  {	fmt.Println("请求"  + url) 	return  ""  } type  LogDecorator struct  {	req ReqI } func  (l LogDecorator)   Handler(url string ) string  {	fmt.Println("日志记录前" ) 	res := l.req.Handler(url) 	fmt.Println("日志记录后" ) 	return  res } type  MonitorDecorator struct  {	req ReqI } func  (m MonitorDecorator)   Handler(url string ) string  {	t1 := time.Now() 	res := m.req.Handler(url) 	sub := time.Since(t1) 	fmt.Println("耗时:" , sub) 	return  res } 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package  decoratorimport  (	"testing"  ) func  TestReq_Handler (t *testing.T)   {	req := Req{} 	logReq := LogDecorator{ 		req: req, 	} 	mReq := MonitorDecorator{ 		req: logReq, 	} 	mReq.Handler("baidu.com" ) } 
 
结构型模式-适配器模式 结构型模式最简单的一种
将一个类的接口转换成客户端期望的另一个接口,从而使不兼容的类能够一起工作
假如你的系统需要继承一个第三方的支付功能,它的功能与你的接口不兼容,转换接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 package  adaptertype  AliPay struct  {} func  (a AliPay)   GetPayPage(price int64 ) string  {	return  "支付宝连接"  } type  WeixinPay struct  {} func  (w WeixinPay)   PayPage(price int64 ) string  {	return  "微信支付连接"  } type  PayI interface  {	PayPage(price int64 ) string  } func  PayPage (pi PayI, price int64 )   string  {	return  pi.PayPage(price) } type  AliPayAdapter struct  {	aliPay *AliPay } func  (a AliPayAdapter)   PayPage(price int64 ) string  {	return  a.aliPay.GetPayPage(price) } 
 
1 2 3 4 5 6 7 8 9 10 11 package  adapterimport  (	"fmt"  	"testing"  ) func  TestPayPage (t *testing.T)   {	fmt.Println(PayPage(WeixinPay{}, 1 )) 	fmt.Println(PayPage(AliPayAdapter{aliPay: &AliPay{}}, 1 )) } 
 
结构型模式-外观模式 提供了一个统一的接口,用于访问子系统中的一组接口
外观模式的核心思想是简化复杂系统的使用,通过提供一个高层接口,隐藏系统的复杂性,使客户端更容易使用
比如:前后端解构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 package  facadeimport  "fmt" type  Inventory struct  {} func  (k Inventory)   Deduction() {	fmt.Println("扣库存" ) } type  Pay struct  {} func  (p Pay)   Pay() {	fmt.Println("下单" ) } type  Logistics struct {}func  (l Logistics)   SendOutGoods() {	fmt.Println("发货" ) } type  Order struct  {	i *Inventory 	p *Pay 	l *Logistics } func  NewOrder ()   *Order {	return  &Order{ 		i: &Inventory{}, 		p: &Pay{}, 		l: &Logistics{}, 	} } func  (o Order)   place() {	o.i.Deduction() 	o.p.Pay() 	o.l.SendOutGoods() } 
 
1 2 3 4 5 6 package  facadeimport  "testing" func  TestLogistics_SendOutGoods (t *testing.T)   {	o := NewOrder() 	o.place() } 
 
结构型模式-享元模式 通过共享对象来减少内存使用和提高性能
核心思想是将对象共享部分(内部状态)与不可共享部分(外部状态)分离,从而减少重复对象的创建
举个例子:共享单车和百度网盘中的文件
核心思想:
各种池技术,连接池,对象池等
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 package  flyweightimport  (	"fmt"  ) type  DB struct  {	id int  } func  NewDB (id int )   *DB {	return  &DB{id} } func  (db DB)   Query(str string ) {	fmt.Printf("使用 %d 连接对象 进行查询操作\n" , db.id) } type  DBPool struct  {	pool   map [int ]*DB 	nextId int  } func  NewDBPool (num int )   *DBPool {	var  pool = map [int ]*DB{}  	for  i := 0 ; i < num; i++ { 		pool[i] = NewDB(i) 	} 	return  &DBPool{ 		pool:   pool, 		nextId: num - 1 , 	} } func  (p *DBPool)   GetDB() *DB {	if  len (p.pool) > 0  { 		for  id, db := range  p.pool { 			delete (p.pool, id) 			return  db 		} 	} 	db := NewDB(p.nextId) 	return  db } func  (p *DBPool)   ReleaseDB(db *DB) {	p.pool[db.id] = db } 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package  flyweightimport  "testing" func  TestNewDBPool (t *testing.T)   {	pool := NewDBPool(10 ) 	db1 := pool.GetDB() 	db1.Query("select * from xxx" ) 	db2 := pool.GetDB() 	db2.Query("select * from xxx" ) 	pool.ReleaseDB(db2) 	db3 := pool.GetDB() 	db3.Query("select * from xxx" ) 	pool.ReleaseDB(db3) }