Go Micro 中用到了的哪些设计模式

以下是对 Go Micro 中涉及的一些设计模式的代码示例及详细解释:

**一、微服务架构模式(服务注册与发现)

**1. 定义服务:

package main

import (
    "context"
    "log"

    "github.com/micro/go-micro/v2"
    "github.com/micro/go-micro/v2/registry"
    "github.com/micro/go-micro/v2/registry/memory"
)

type Greeter struct{}

func (g *Greeter) Hello(ctx context.Context, req *HelloRequest, rsp *HelloResponse) error {
    rsp.Greeting = "Hello " + req.Name
    return nil
}

type HelloRequest struct {
    Name string
}

type HelloResponse struct {
    Greeting string
}

func main() {
    // 创建内存注册中心
    reg := memory.NewRegistry()

    // 创建服务
    service := micro.NewService(
        micro.Name("greeter"),
        micro.Registry(reg),
    )

    // 初始化服务
    service.Init()

    // 注册服务
    if err := micro.RegisterHandler(service.Server(), new(Greeter)); err!= nil {
        log.Fatal(err)
    }

    // 启动服务
    if err := service.Run(); err!= nil {
        log.Fatal(err)
    }
}

解释:
 - **微服务架构模式**:将一个大型的应用程序拆分为多个小型的、独立的服务,每个服务专注于特定的业务功能。在这个例子中,我们定义了一个名为`Greeter`的服务,它提供了一个`Hello`方法用于向用户打招呼。
 - **服务注册与发现**:服务提供者将自己的服务信息注册到注册中心,服务消费者从注册中心获取服务提供者的地址信息,然后进行调用。这有助于实现服务的动态发现和负载均衡。在这个例子中,我们创建了一个内存注册中心`memory.NewRegistry()`,并在创建服务时通过`micro.Registry(reg)`将其传入。这样,当服务启动时,它会自动注册到注册中心,其他服务可以通过注册中心发现这个服务并进行调用。

**二、代理模式(RPC 代理)**

在 Go Micro 中,当客户端发起 RPC 请求时,实际上是通过一个代理对象进行的。以下是一个简单的客户端代码示例:

解释:
 - **代理模式**:为其他对象提供一种代理以控制对这个对象的访问。在 Go Micro 中,客户端发起的 RPC 请求实际上是通过一个代理对象发送到服务端。代理对象负责处理网络通信、序列化和反序列化等操作,对客户端隐藏了底层的通信细节。
 - 在这个例子中,`greeterClient := greeter.NewGreeterService("greeter", service.Client())`创建了一个代理对象,它代表了远程的`Greeter`服务。当调用`greeterClient.Hello`时,实际上是通过这个代理对象将请求发送到远程服务,并接收响应。代理对象负责处理网络通信、序列化和反序列化等操作,使得客户端可以像调用本地方法一样调用远程服务。

**三、门面模式(服务接口封装)**

package main

import (
    "context"
    "log"

    "github.com/micro/go-micro/v2"
    greeter "github.com/micro/examples/greeter/srv/proto/greeter"
)

func main() {
    // 创建新的服务
    service := micro.NewService(micro.Name("greeter-client"))
    service.Init()

    // 创建 Greeter 服务的客户端
    greeterClient := greeter.NewGreeterService("greeter", service.Client())

    // 调用远程服务
    rsp, err := greeterClient.Hello(context.Background(), &greeter.HelloRequest{Name: "John"})
    if err!= nil {
        log.Fatal(err)
    }

    log.Println(rsp.Greeting)
}

以服务端为例:

package main

import (
    "log"

    "github.com/micro/go-micro/v2"
    "github.com/micro/go-micro/v2/server"
)

type Greeter struct{}

func (g *Greeter) Hello(ctx context.Context, req *HelloRequest, rsp *HelloResponse) error {
    rsp.Greeting = "Hello " + req.Name
    return nil
}

type HelloRequest struct {
    Name string
}

type HelloResponse struct {
    Greeting string
}

func main() {
    service := micro.NewService(
        micro.Name("greeter"),
    )

    service.Init()

    // 注册服务到 Micro 框架
    if err := micro.RegisterHandler(service.Server(), new(Greeter)); err!= nil {
        log.Fatal(err)
    }

    if err := service.Run(); err!= nil {
        log.Fatal(err)
    }
}

解释:
 - **门面模式**:为子系统中的一组接口提供一个一致的界面,定义了一个高层接口,使得子系统更容易使用。在 Go Micro 中,为开发者提供了简洁的接口来定义服务。例如,通过实现一个结构体的方法来定义服务的处理逻辑,然后使用`micro.RegisterHandler`将服务注册到框架中。这封装了复杂的网络通信和服务管理逻辑,让开发者专注于业务逻辑的实现。
 - 在这个例子中,我们定义了一个`Greeter`结构体,实现了`Hello`方法来处理请求。然后,通过`micro.RegisterHandler`将这个服务注册到 Micro 框架中。框架会自动处理网络通信、请求路由等复杂操作,开发者只需要关注业务逻辑的实现。

**四、插件模式(可插拔组件)**

以使用不同的注册中心插件为例:

package main

import (
    "log"

    "github.com/micro/go-micro/v2"
    "github.com/micro/go-micro/v2/registry"
    "github.com/micro/go-micro/v2/registry/etcd"
)

type Greeter struct{}

func (g *Greeter) Hello(ctx context.Context, req *HelloRequest, rsp *HelloResponse) error {
    rsp.Greeting = "Hello " + req.Name
    return nil
}

type HelloRequest struct {
    Name string
}

type HelloResponse struct {
    Greeting string
}

func main() {
    // 创建 etcd 注册中心
    reg := etcd.NewRegistry(
        registry.Addrs("localhost:2379"),
    )

    service := micro.NewService(
        micro.Name("greeter"),
        micro.Registry(reg),
    )

    service.Init()

    if err := micro.RegisterHandler(service.Server(), new(Greeter)); err!= nil {
        log.Fatal(err)
    }

    if err := service.Run(); err!= nil {
        log.Fatal(err)
    }
}

解释:
 - **插件模式**:允许软件的某些部分可以被动态地替换或扩展,而不影响整体的功能。在 Go Micro 中,支持各种插件,如注册中心插件、传输插件、编解码插件等。这种设计允许开发者根据具体需求选择不同的插件,实现了高度的可扩展性和灵活性。
 - 在这个例子中,我们使用了`etcd.NewRegistry`创建了一个 etcd 注册中心插件,并在创建服务时通过`micro.Registry(reg)`将其传入。这样,我们可以轻松地切换注册中心插件,而不需要修改服务的核心代码。例如,如果我们想要使用 Consul 注册中心,只需要引入 Consul 的插件包,并使用`consul.NewRegistry`创建注册中心即可。

**五、装饰器模式(中间件)**

package main

import (
    "context"
    "log"

    "github.com/micro/go-micro/v2"
    "github.com/micro/go-micro/v2/server"
)

type Greeter struct{}

func (g *Greeter) Hello(ctx context.Context, req *HelloRequest, rsp *HelloResponse) error {
    rsp.Greeting = "Hello " + req.Name
    return nil
}

type HelloRequest struct {
    Name string
}

type HelloResponse struct {
    Greeting string
}

func logMiddleware(fn server.HandlerFunc) server.HandlerFunc {
    return func(ctx context.Context, req server.Request, rsp interface{}) error {
        log.Println("Before handling request")
        err := fn(ctx, req, rsp)
        log.Println("After handling request")
        return err
    }
}

func main() {
    service := micro.NewService(
        micro.Name("greeter"),
    )

    service.Init()

    // 使用中间件装饰服务处理函数
    service.Server().Handle(
        service.Server().NewHandler(&Greeter{}, logMiddleware),
    )

    if err := service.Run(); err!= nil {
        log.Fatal(err)
    }
}

解释:
 - **装饰器模式**:动态地给一个对象添加一些额外的职责,而不改变其结构。在 Go Micro 中,允许使用中间件来装饰服务的处理函数。中间件可以在请求处理的前后执行一些额外的操作,如日志记录、身份验证、性能监控等。这类似于装饰器模式,为服务添加额外的功能而不修改服务的核心逻辑。
 - 在这个例子中,我们定义了一个中间件函数`logMiddleware`,它在服务处理函数执行前后打印日志。然后,在注册服务处理函数时,使用`service.Server().NewHandler(&Greeter{}, logMiddleware)`将中间件应用到服务处理函数上。这样,每次请求到达服务时,中间件会先打印日志,然后调用服务处理函数,最后再打印日志。这种方式可以在不修改服务核心逻辑的情况下,为服务添加日志记录功能。如果需要添加其他功能,如身份验证、性能监控等,只需要定义相应的中间件函数,并将其应用到服务处理函数上即可。

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值