设计模式golang-结构型模式
一、适配器模式
1.作用
将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
2.举例
- 已经存在的接口
//不可充电电池使用接口
type NonRechargeableBattery interface {
Use()
}
- 客户希望的接口
//可充电电池使用接口
type RechargeableBattery interface {
Use()
Charge()
}
- 已经存在的对象和实现方法
//不可充电电池A
type NonRechargeableA struct {
}
func (NonRechargeableA) Use() {
fmt.Println("NonRechargeableA using ")
}
1、对象适配器
- 对对象进行适配
//适配可充电电池使用接口
type AdapterNonToYes struct {
NonRechargeableBattery
}
func (AdapterNonToYes) Charge() {
fmt.Println("AdapterNonToYes Charging")
//nothing to do ,just adapt for RechargeableBattery's interface
}
- 适配效果
func TestAdapter(t *testing.T) {
battery := AdapterNonToYes{NonRechargeableA{}}
battery.Use()
battery.Charge()
}
2、接口适配器
- 对接口进行适配
type RechargeableBatteryAbstract struct {
}
func (RechargeableBatteryAbstract) Use() {
fmt.Println("RechargeableBatteryAbstract using")
}
func (RechargeableBatteryAbstract) Charge() {
fmt.Println("RechargeableBatteryAbstract Charging")
}
- 对原有不可充电电池A适配新的接口
//不可充电电池A
type NonRechargeableA struct {
RechargeableBatteryAbstract
}
func (NonRechargeableA) Use() {
fmt.Println("NonRechargeableA using ")
}
- 适配效果
func TestAdapterFunc(t *testing.T) {
battery := NonRechargeableA{
RechargeableBatteryAbstract: RechargeableBatteryAbstract{},
}
battery.Use()
battery.Charge()
}
二、桥接模式
1.作用
把抽象化与实现化解耦,使得二者可以独立变化。通过提供抽象化和实现化之间的桥接结构,来实现二者的解耦。
2.举例
1、创建桥接实现接口
//请求接口
type Request interface {
HttpRequest() (*http.Request, error)
}
2、抽象化客户端请求行为
//客户端
type Client struct {
Client *http.Client
}
func (c *Client) Query(req Request) (resp *http.Response, err error) {
httpreq, _ := req.HttpRequest()
resp, err = c.Client.Do(httpreq)
return
}
3、创建实现了Request接口的实体桥接实现结构体
type CdnRequest struct {
}
func (cdn *CdnRequest) HttpRequest() (*http.Request, error) {
return http.NewRequest("GET", "/cdn", nil)
}
type LiveRequest struct {
}
func (cdn *LiveRequest) HttpRequest() (*http.Request, error) {
return http.NewRequest("GET", "/live", nil)
}
4、桥接效果
func TestBridge(t *testing.T) {
client := &Client{http.DefaultClient}
cdnReq := &CdnRequest{}
fmt.Println(client.Query(cdnReq))
liveReq := &LiveRequest{}
fmt.Println(client.Query(liveReq))
}
三、组合模式
1.作用
将对象组合成树形结构以表示"部分-整体"的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
2.举例
1、创建Department 结构体,该结构体带有 Employee 对象的列表。
package pattern
import "fmt"
//
// 组合模式 将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
//
type Department struct {
List map[string]*Department
Parent *Department
Name string
Id string
}
// 批量添加子节点
func (this *Department) Add(departments ...*Department) {
for _, department := range departments {
department.AddTo(this)
}
}
// 添加到对应的父节点
func (this *Department) AddTo(parent *Department) {
this.Parent = parent
parent.add(this)
}
// 添加子节点
func (this *Department) add(department *Department) {
if this.List == nil {
this.List = make(map[string]*Department, 0)
}
this.List[department.Id] = department
}
// 查找子节点
func (this *Department) Find(id string) (department *Department) {
department, ok := this.List[id]
if !ok {
for _, de := range this.List {
department = de.Find(id)
if nil != department {
return
}
}
return
}
return
}
// 移除子节点
func (this *Department) Remove(id string) (department *Department) {
department, ok := this.List[id]
if !ok {
for _, de := range this.List {
department = de.Remove(id)
if nil != department {
return
}
}
return
}
delete(this.List, id)
return
}
// 遍历
func (this *Department) ReadList() {
fmt.Printf("Node :%s(%s) \n the children: \n", this.Id, this.Name)
for _, de := range this.List {
de.ReadList()
}
}
2、创建和打印部门的层次结构。
func TestComposite(t *testing.T) {
root := &Department{Name: "root", Id: "0010"}
children1 := &Department{Name: "network", Id: "00010"}
children2 := &Department{Name: "forward", Id: "00011"}
root.Add(children1, children2)
children1.Add(&Department{Name: "network1", Id: "0001010"})
root.Find("0001010").ReadList()
root.Remove("00010").ReadList()
root.ReadList()
}
四、装饰器模式
1.作用
动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。
2.举例
1、创建一个接口
// 接口
type MessageBuilder interface{
Build(messages ... string) string
}
2、实现这个接口
// 基本信息构造器
type BaseMessageBuilder struct {
}
func(b *BaseMessageBuilder)Build(messages ... string) string{
return strings.Join(messages,",")
}
3、使用装饰器装饰这个接口
// 引号装饰器
type QuoteMessageBuilderDecorator struct {
Builder MessageBuilder
}
func(q *QuoteMessageBuilderDecorator)Build(messages ... string) string{
return "\""+q.Builder.Build(messages...)+"\""
}
// 大括号装饰器
type BraceMessageBuilderDecorator struct {
Builder MessageBuilder
}
func(b *BraceMessageBuilderDecorator)Build(messages ... string) string{
return "{"+b.Builder.Build(messages...)+"}"
}
4、装饰器效果
func TestDecorator(t *testing.T) {
var MB MessageBuilder
MB = &BaseMessageBuilder{}
fmt.Println(MB.Build("hello world"))
MB = &QuoteMessageBuilderDecorator{MB}
fmt.Println(MB.Build("hello world"))
MB = &BraceMessageBuilderDecorator{MB}
fmt.Println(MB.Build("hello world"))
}
2.举例二
方法前后加入日志打印或其他处理
type Object func(int) int
func LogDecorate(fn Object) Object {
return func(n int) int {
log.Println("Starting the execution with the integer", n)
result := fn(n)
log.Println("Execution is completed with the result", result)
return result
}
}
五、外观模式
1.作用
隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口。
为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
2.举例
1、内部功能
//程序员
type Coder struct {
}
func (c *Coder) Coding() {
fmt.Println("Coding ....")
}
//测试
type Tester struct {
}
func (t *Tester) Testing() {
fmt.Println("Testing ....")
}
//产品
type ProductPlanner struct {
}
func (p *ProductPlanner) Planing() {
fmt.Println("Planing ....")
}
//运维
type MaintenancePeople struct {
}
func (m *MaintenancePeople) Releasing() {
fmt.Println("Releasing ....")
}
2、创建外观结构体
// 公司
// 拥有产品策划、程序员、测试人员,运维人员
// 通过公司这个外观对外提供服务,
// 而不是直接通过某个类型人员对外服务(虽然最终提供服务的也是某个类型的人员)
type Company struct {
ProductPlanner
Coder
Tester
MaintenancePeople
}
3、对外展示效果
func TestFacade(t *testing.T) {
com := &Company{}
//生产产品
com.Producing()
}
// 对外提供生产产品服务
// 需要各个类型人员合作,但细节不对外公开的
func (com *Company) Producing() {
// 策划产品
com.Planing()
// 编码实现
com.Coding()
// 测试产品
com.Testing()
// 发布产品
com.Releasing()
}
六、享元模式
1.作用
- 主要用于减少创建对象的数量,以减少内存占用和提高性能。
- 在有大量对象时,有可能会造成内存溢出,我们把其中共同的部分抽象出来,如果有相同的业务请求,直接返回在内存中已有的对象,避免重新创建。
- 通常与工厂模式一起使用。
2.举例
数据库连接池
// 数据库连接池
type DbConnectPool struct {
ConnChan chan *DbConnect
}
func NewDbConnectPool(chanLen int) *DbConnectPool {
return &DbConnectPool{ConnChan: make(chan *DbConnect, chanLen)}
}
func (dc *DbConnectPool) Get() *DbConnect {
select {
case conn := <-dc.ConnChan:
return conn
default:
// 无则新建
return new(DbConnect)
}
}
func (dc *DbConnectPool) Put(conn *DbConnect) {
select {
case dc.ConnChan <- conn:
return
default:
// 满则丢弃
return
}
}
// 数据库连接
type DbConnect struct {
}
func (*DbConnect) Do() {
fmt.Println("connect......doing....")
}
七、代理模式
1.作用
-
意图: 为其他对象提供一种代理以控制对这个对象的访问。
-
优点: 1、职责清晰。 2、高扩展性。 3、智能化。
-
注意事项:
1、和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。
2、和装饰器模式的区别:装饰器模式为了增强功能,而代理模式是为了加以控制。
2.举例
1、定义接口
type Device interface {
Read()([]byte,error)
Write(word []byte)error
}
2、创建实现类
type HardDisk struct {
storage []byte
}
func(h *HardDisk)Read()([]byte,error){
return h.storage,nil
}
func(h *HardDisk)Write(word []byte)error{
h.storage=word
return nil
}
3、代理实现类
type HardDiskProxy struct {
OpId string
hd *HardDisk
}
func(h *HardDiskProxy)Read()([]byte,error){
if !h.permission("read") {
return nil ,errors.New("You don't have permission to read")
}
return h.hd.Read()
}
func(h *HardDiskProxy)Write(word []byte)error{
if !h.permission("wrire") {
return errors.New("You don't have permission to write")
}
return h.hd.Write(word)
}
// 权限判断
func(h *HardDiskProxy)permission(tag string)bool{
if h.OpId=="admin"{
return true
}
if h.OpId=="reader"&&tag=="read"{
return true
}
if h.OpId=="writer"&&tag=="wrire"{
return true
}
return false
}
八、参考资料
https://pkg.go.dev/github.com/BPing/golang_design_pattern/pattern