美文网首页
go设计模式之结构型模式

go设计模式之结构型模式

作者: 浩成聊技术 | 来源:发表于2022-12-11 01:26 被阅读0次

结构型模式解决什么问题

结构模式关注类和对象的组合,解决如何将类和对象组装成较大结构的同时,保持结构的灵活和可复用性。

1.装饰模式(俄罗斯套娃)

装饰模式是对基类进行包装(装饰)从而为对象增加新功能或改变原有功能,操作对象和装饰器对象由于实现了同一接口,
因而操作对象可以用装饰器进行多次(套娃式)封装,对象将获得所有装饰器作用叠加后的功能。

装饰模式图解

下面代码描述了如何通过层层装饰返回一个满足顾客要求的披萨,并计算价格:

package main

import "fmt"

type IPizza interface {
    getPrice() int
}

// 基类: 素食披萨
type Vegetable struct {
}

func (v Vegetable) getPrice() int {
    return 10
}

// 装饰器1: 奶酪装饰器
type Cheese struct {
    pizza IPizza
}

func (c Cheese) getPrice() int {
    return c.pizza.getPrice() + 3
}

// 装饰器2:
type Tomato struct {
    pizza IPizza
}

func (c Tomato) getPrice() int {
    return c.pizza.getPrice() + 4
}

func main() {

    vegetablePizza := Vegetable{}

    cheeseVegePizza := Cheese{vegetablePizza}

    tomatoCheeseVegePizza := Tomato{cheeseVegePizza}

    fmt.Printf("加了番茄和奶酪的披萨最终价格:%d\n", tomatoCheeseVegePizza.getPrice())

}


// output
// 加了番茄和奶酪的披萨最终价格:17

2.适配器模式

适配器模式可以通过一个中间层使不兼容的两个对象互相合作,适配器接收对象对其调用,并将此调用装换为对另一个对象的调用。适配就好比现实世界中的扩展坞将A和B
两个接口之间做了一层装换。

适配器模式图解

下面代码描述了如何通过适配器让只支持usb的windows电脑,也能使用雷电接口:

package main

import "fmt"

type Computer interface {
    InsertIntoLightningPort()
}

type Client struct {
}

// 给电脑插入雷电接口
func (t Client) InsertLightIntoComputer(c Computer) {
    c.InsertIntoLightningPort()
}

type Mac struct {
}

// mac电脑使用雷电接口
func (m Mac) InsertIntoLightningPort() {
    fmt.Println("给mac电脑插入雷电接口")
}

type Windows struct {
}

// windows电脑使用usb接口
func (m Windows) InsertIntoUsbPort() {
    fmt.Println("给windows电脑插入usb接口")
}

type WindowsAdapter struct {
    windows Windows
}

// 适配器 将雷电接口转为usb接口
func (w WindowsAdapter) InsertIntoLightningPort() {
    fmt.Println("转换雷电接口为usb接口")
    w.windows.InsertIntoUsbPort()
}

func main() {
    mac := Mac{}
    client := Client{}

    client.InsertLightIntoComputer(mac)

    windows := Windows{}

    adapter := WindowsAdapter{windows: windows}

    client.InsertLightIntoComputer(adapter)
}


// output
// 给mac电脑插入雷电接口
// 转换雷电接口为usb接口
// 给windows电脑插入usb接口

3.代理模式

代理模式可以替代原对象,处理对原对象的调用,通常会在对原对象的调用前后做一些同一的处理,例如nginx代理web应用处理请求,在流量真正到达
web应用程序前做请求的负载均衡,之后决定将请求转发给哪台服务器。

代理模式图解

下面代码实现了nginx代理web应用程序做接口限流:

package main

import "fmt"

// web服务应该具有处理请求的能力
type Server interface {
    handleRequest(url, method string) (int, string)
}

// web应用程序
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 200, "User Created Success!"
    }
    return 404, "404 Not Found"
}

// nginx 代理web应用处理请求,做api接口请求限流
type NginxServer struct {
    application  Application
    MaxReqNum    int            // 最大请求数
    LimitRateMap map[string]int // 缓存每个接口的请求数
}

func NewNginxServer(app Application, max int) *NginxServer {
    return &NginxServer{
        application:  app,
        MaxReqNum:    max,
        LimitRateMap: make(map[string]int),
    }
}

// 代理web应用请求
func (n NginxServer) handleRequest(url, method string) (int, string) {
    if !n.checkReqRate(url) {
        return 403, "Not Allowed"
    }

    // 接口限流后转发请求到真实web应用
    return n.application.handleRequest(url, method)
}

// 接口限流和缓存
func (n *NginxServer) checkReqRate(url string) bool {
    reqNum := n.LimitRateMap[url]

    if reqNum >= n.MaxReqNum {
        return false
    }
    n.LimitRateMap[url]++

    return true
}

func main() {

    nginx := NewNginxServer(Application{}, 2)
    respCode, respBody := nginx.handleRequest("/app/status", "GET")
    fmt.Printf("URL:%s \n返回状态码:%d,响应内容:%s \n\n", "/app/status", respCode, respBody)

    respCode, respBody = nginx.handleRequest("/app/status", "GET")
    fmt.Printf("URL:%s \n返回状态码:%d,响应内容:%s \n\n", "/app/status", respCode, respBody)

    // 超过了最大限流数 返回403
    respCode, respBody = nginx.handleRequest("/app/status", "GET")
    fmt.Printf("URL:%s \n返回状态码:%d,响应内容:%s \n\n", "/app/status", respCode, respBody)

    respCode, respBody = nginx.handleRequest("/create/user", "POST")
    fmt.Printf("URL:%s \n返回状态码:%d,响应内容:%s \n\n", "/create/user", respCode, respBody)

}

/* output
URL:/app/status
返回状态码:200,响应内容:Ok

URL:/app/status
返回状态码:200,响应内容:Ok

URL:/app/status
返回状态码:403,响应内容:Not Allowed

URL:/create/user
返回状态码:200,响应内容:User Created Success!

*/

4.总结

下面是分别是这3种设计模式的常见应用场景:

设计模式 常见应用场景
装饰器模式 不修改原有对象结构,运行时为对象新增额外功能
适配器模式 想使用某个类,但这个类和其他代码不兼容时,创建一个中间层类
代理模式 延迟初始化真实对象,先使用虚拟代理,请求代理(记录日志,请求缓存,请求限流,代理远程服务)

相关文章

  • 《设计模式之美》- 23种设计模式

    学习《设计模式之美》笔记。 23 种经典设计模式共分为 3 种类型,分别是创建型、结构型和行为型 创建型模式 创建...

  • Golang 设计模式之-装饰模式

    Golang 设计模式之-装饰模式 最近在温习设计模式,虽然面向对象不是go的特长,但用go实现的设计模式,比ja...

  • 第1章 设计模式概述

    一、设计模式的概念 二、设计模式的历史 三、设计模式的要素 四、设计模式的分类 ■ 创建型设计模式 ■ 结构型设计...

  • 23种设计模式总结一

    23 种经典设计模式共分为 3 种类型,分别是创建型、结构型和行为型。 一、创建型设计模式 创建型设计模式包括:单...

  • 设计模式简单总结(待完善)

    设计模式简单总结 设计模式可以分为:创建型,结构型,行为型三种模式。 1 创建型模式 1.1 单例模式 用来指定某...

  • android常用设计模式

    26种设计模式 创建型设计模式[5] 单例模式,工厂模式,抽象工厂模式,建造模式,原型模式,[简单工厂模式] 结构...

  • 23种设计模式总结二

    23 种经典设计模式共分为 3 种类型,分别是创建型、结构型和行为型。 结构型设计模式 结构型模式就是一些类或对象...

  • Nodejs实现23种设计模式-1.简单工厂模式

    Nodejs实现24种设计模式--简单工厂模式 导语:24种设计模式,分为三大类,创建型、结构型和行为型。这些模式...

  • 项目开发-------iOS设计模式

    iOS的设计模式大体可以分为以下几种设计模式 1.创建型:单例设计模式、抽象工厂设计模式 2.结构型:MVC 模式...

  • 状态模式,命令模式和策略模式的区别

    设计模式中有三个模式State, Command, Strategy,这三种设计模式都是行为型设计模式,在结构上又...

网友评论

      本文标题:go设计模式之结构型模式

      本文链接:https://www.haomeiwen.com/subject/bwptqdtx.html