首页 > 其他分享 >golang实现设计模式之享元模式总结-代码、优缺点、适用场景

golang实现设计模式之享元模式总结-代码、优缺点、适用场景

时间:2023-06-02 11:14:22浏览次数:54  
标签:享元 return name object golang flyweight func 设计模式

享元模式是一种结构型的设计模式,通过共享细粒度对象实现对象的复用,从而达到减少对象创建与销毁,减少内存消耗,其本质是本质是缓存共享对象,降低内存消耗。

享元模式的定义提出了两个要求,细粒度和共享对象。因为要求细粒度,所以不可避免地会使对象数量多且性质相近,此时我们就将这些对象的信息分为两个部分:内部状态和外部状态。[1]

  • 内部状态指对象共享出来的信息,存储在享元信息内部,并且不回随环境的改变而改变;
  • 外部状态指对象得以依赖的一个标记,随环境的改变而改变,不可共享。

比如,连接池中的连接对象,保存在连接对象中的用户名、密码、连接URL等信息,在创建对象的时候就设置好了,不会随环境的改变而改变,这些为内部状态。而当每个连接要被回收利用时,我们需要将它标记为可用状态,这些为外部状态。

在使用享元模式时,我们需要注意与单例模式的区别:

  • 1.如果请求对象都一样,可以使用单例模式
  • 2.如果请求对象相似,可以共享多个共同属性

结构

  • 1.抽象享元角色(Flyweight):即享元的接口,定义相关方法
  • 2.具体享元(Concrete Flyweight)角色:实现享元接口
  • 3.享元工厂(Flyweight Factory)角色:管理享元的创建销毁等

优缺点

  • 优点
    1.缩小对象的创立,升高内存中对象的数量,升高零碎的内存,提高效率。
    2.缩小内存之外的其余资源占用。

  • 缺点
    1.为了使对象可以共享,需要将一些不能共享的状态外部化,这将增加程序的复杂性。
    2.读取享元模式的外部状态会使得运行时间稍微变长。

适用场景
1.系统中存在大量相同或相似的对象,这些对象耗费大量的内存资源,如需要缓冲池,数据库连接池。
2.大部分的对象可以按照内部状态进行分组,且可将不同部分外部化,这样每一个组只需保存一个内部状态。
3.由于享元模式需要额外维护一个保存享元的数据结构,所以应当在有足够多的享元实例时才值得使用享元模式。

代码实现
在 golang 实现中,我们可以用 map 结构,也可以用 sync.Pool 来实现,sync.Pool则封装更好,具体看需求。

package main

import (
   "fmt"
   "sync"
)

/*
业务场景描述:
- 租车场景,客户像车行租车,如果车行有车直接租给客户,没有则从车行的其他分部调车分配
场景角色:
- 1.抽象享元,接口,实现产品具有属性
- 2.具体享元,类,实现抽象享元
- 3.享元工厂,控制和管理享元
- 4.客户端,请求获取产品

 */

// 1.抽象享元-便于扩展
type iFlyweight interface {
   drive()
}

// 2.具体享元
type flyweight struct {
   name string
}

func NewFlyweight(name string) *flyweight {
   return &flyweight{
      name: name,
   }
}

func (r *flyweight) drive()  {
   fmt.Printf("the car [%s] is driving on the road.\n", r.name)
}

// 3.享元工厂
type flyweightFactory struct {
   pool map[string]*flyweight
}

func NewFlyweightFactory() *flyweightFactory {
   return &flyweightFactory{
      pool: make(map[string]*flyweight),
   }
}

func (r *flyweightFactory) Get(name string) *flyweight {
   object, ok := r.pool[name]
   if !ok {
      object = r.schedule(name)
      r.pool[name] = object
   }

   return object
}

// 相当于新建对象
func (r *flyweightFactory) schedule(name string) *flyweight {
   fmt.Printf("车行从其他分部调入: [%s]\n", name)
   return &flyweight{name}
}

// 用完之后的还车
func (r *flyweightFactory ) Put(object *flyweight) error {
   r.pool[object.name] = object
   return nil
}

// sync.pool 实现,封装更好,直接get、put即可
type flyweightFactoryV2 struct {
   pool sync.Pool
}

func NewFlyweightFactoryV2() *flyweightFactoryV2 {
   factory := &flyweightFactoryV2{}
   factory.pool.New = func() any {
      return new(flyweight)
   }

   return factory
}

func (r *flyweightFactoryV2) Get(name string) *flyweight {
   // 使用时需要断言
   object := r.pool.Get().(*flyweight)

   return r.warp(name, object)
}

func (r *flyweightFactoryV2) warp(name string, fly *flyweight) *flyweight {
   fmt.Printf("正在租出一辆车: [%s]\n", name)
   fly.name = name
   return fly
}

// 用完之后的还车
func (r *flyweightFactoryV2) Put(object *flyweight) error {
   r.pool.Put(object)
   return nil
}

// 4.客户端
func main()  {
   // map实现共享池
   fac := NewFlyweightFactory()
   // 获取对象
   car := fac.Get("BMW")
   // 使用对象
   car.drive()
   // 用完还车
   _ = fac.Put(car)

   // 再次租车
   car1 := fac.Get("BMW")

   // 租其他车
   car2 := fac.Get("Benz")

   // 直接还车
   fac.Put(car1)
   fac.Put(car2)

   /* result:
   车行从其他分部调入: [BMW]
   the car [BMW] can driving on the road.
   车行从其他分部调入: [Benz]
    */

   // sync.Pool实现共享池
   facV2 := NewFlyweightFactoryV2()
   // rent
   car3 := facV2.Get("RR")

   // use
   car3.drive()

   // return car
   facV2.Put(car3)
}

参考:

标签:享元,return,name,object,golang,flyweight,func,设计模式
From: https://www.cnblogs.com/davis12/p/17451198.html

相关文章

  • golang依赖注入工具digo
    golang依赖注入工具digo工具地址:https://github.com/werbenhu/digo特性使用注释中的注解自动代码生成自动检测循环依赖编译时期依赖注入自动初始化支持实例组的管理快速开始更多示例请参考:examples编写代码和注解packagemainimport( "log" "github.com/werbe......
  • Java设计模式之单例模式
    一、何谓单例模式?单例模式,也叫单子模式,是一种常用的软件设计模式,属于创建型模式的一种。在应用这个模式时,单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。比如在某个服务器程序中,该服务器的配置信息存放在一......
  • javascript设计模式-责任链
    责任链可以用来消除请求的发送者和接收者之间的耦合,这是通过实现一个由隐式地对请求进行处理的对象组成的链而做到的。链中的每个对象可以处理请求,也可以将其传给下一个对象。JS内部就使用了这种模式来处一事件捕获和冒泡问题。一般的结构如下:发送者知道链中的第一个接收者,它向这个......
  • golang实现设计模式之构建者模式总结-代码、优缺点、适用场景
    构建者模式也是一种创建型的设计模式,该模式将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的对象。大白话就是,构建者模式,从输出角度看依然是创建个对象实例,但是构建者模式更关注创建的细节,或者说一个对象的创建可以拆分为多个步骤,所有的步骤完成才创建出这个对......
  • Go设计模式
    Go-设计模式整理参考:Go设计模式24-总结(更新完毕)-Mohuishou(lailin.xyz)go设计模式实现,包含23种常见的设计模式实现设计模式学习的重点是什么?设计原则,以及设计模式的使用场景和优缺点,实现相对来说还没有那么重要如果是常见的设计模式是武术招式,那么设计原则就是内......
  • 优雅实现golang默认参数
    原生的golang中,函数定义不支持默认参数。但是在实际开发过程中,经常会有些参数用户可以不关心或者可以根据实际情况去定制实现,这个时候需要使用到默认参数,在C++中,函数的定义和实现本来就支持默认参数,如果需要在golang中实现默认参数,可以参考一下做法: packagemainimport"fmt......
  • golang vscode开发环境配置
    1.下载go安装包并安装官网下载地址2.下载vscode并安装官网下载地址3.安装vscodego语言开发扩展(插件)4.切换国内下载源,cmd输入如下代码goenv-wGO111MODULE=ongoenv-wGOPROXY=https://goproxy.cn,direct5.安装vscodego开发工具包windows下vscodeCtrl+Shift+P找......
  • Java 微服务中的聚合器设计模式示例
    微服务架构中的聚合器设计模式是一种设计模式,用于通过聚合多个独立的微服务的响应来组成一个复杂的服务。它也是与SAGA、CQRS和EventSourcing一起的基本微服务设计模式之一。当客户端请求需要跨多个微服务分布的数据或功能时,此模式是合适的。可以提高系统的性能和可扩展性通过允许......
  • 什么是微服务中的断路器设计模式?如何实施?
    大家好,微服务设计模式是Java开发人员需要学习的非常重要的概念,不仅是为了创建一个健壮的、可扩展的、高性能的微服务架构,也是为了在Java开发人员面试中取得好成绩。过去,我分享了几种微服务设计模式,如eEventSourcing、SAGA、DatabasePerMicroservices、CQRS、APIGateway......
  • golang之recover
    recover是什么golang的recover是一个内置函数,用于在发生panic时恢复程序的控制流。当程序发生panic时,程序会停止执行当前的函数,并向上层函数传递panic,直到被recover函数捕获。recover函数必须在defer语句中调用,否则无法捕获panic。如果没有发生panic或者没有被recover函数捕获,程序......