《golang设计模式》第二部分·结构型模式-06-享元模式(Flyweight)

news2024/11/24 7:00:00

文章目录

  • 1. 概述
    • 1.1角色
    • 1.2 类图
  • 2. 代码示例
    • 2.1 设计
    • 2.2 代码
    • 2.3 类图示例

1. 概述

享元(Flyweight)模式采用共享方式向客户端提供数量庞大的细粒度对象。

所谓细粒度对象,是指实现了业务细节并相互独立的对象。细粒度对象是一种相对概念,一般不会进行更小粒度的拆分。

1.1角色

  • 抽象享元(Flyweight):
    • 通常是一个接口或抽象类
    • 它声明了具体享元类的公共方法
  • 具体享元(Concrete Flyweight)
    • 实现了抽象享元
    • 包含内部状态和外部状态
      • 内部状态:不可以被改变
      • 外部状态:可以被改变
    • 通常每一个具体享元类提供唯一的享元对象(可参考单例模式)
  • 享元工厂(Flyweight Factory):
    • 负责创建和管理享元角色
    • 它是享元的聚合,通常为:HashMap[key]Flyweight

当客户对象请求一个享元 对象时,享元工厂检査系统中是否存在符合要求的享元对象,如果存在则提供给客户;如果不存在 的话,则创建一个新的享元对象。

1.2 类图

Client
FlyweightFactory
-flyweights:HashMap
+GetFlyweight(key:key)
ConcreteFlyweight
-IntrinsicState:Data
-extrinsicState:Data
+service(extrinsicStat:Data)
«interface»
Flyweight
+service(extrinsicState:Date)

2. 代码示例

2.1 设计

  • 定义一个抽象棋子(抽象享元)
  • 它的实现是 黑子、白子两个实际享元
    • 它的不变部分:颜色、形状
      • 它的Create()方法用来设置这些不可变部分
    • 它的可变部分:位置
      • 它的Set()方法用来设置位置
  • 定义一个享元工厂
    • 它应该包含两个享元
      • 1号享元黑子
      • 2号享元白子
    • 它的Get方法用来生产棋子
      • 如果有需要的棋子则返回查到的结果
      • 如果没有需要的棋子则创建该棋子
  • 调用
    • 创建一个享元工厂
    • 下第一颗子
      • 用享元工厂Get()方法实例化一个黑子
        • 此时享元工厂中没有黑子享元,它会创建一个黑子享元并返回。(当然这个过程用户看不出来,想看的话你可以在这之前打印享元工厂或者调试)
      • 用黑子的Set()方法设置这颗棋子的位置
      • 查看结果
    • 下第二颗子,也是白子的第一颗子
      • 用享元工厂Get()方法实例化一个白子

        • 此时享元工厂中没有白子享元,它会创建一个白子享元并返回。(当然这个过程用户看不出来,想看的话你可以在这之前打印享元工厂或者调试)
      • 用黑子的Set()方法设置这颗棋子的位置

      • 查看结果

    • 下第三颗子,也是黑子的第三颗子
      • 用享元工厂Get()方法实例化一个黑子
        • 此时享元工厂已经有黑子享元,它会直接返回这个享元。(当然这个过程用户看不出来,想看的话你可以在这之前打印享元工厂或者调试)
      • 用黑子的Set()方法设置这颗棋子的位置
      • 查看结果

2.2 代码

package main

import (
	"errors"
	"fmt"
)

//定义一个抽象享元
type Flyweight interface {
	Create()
	Set(x int64, y int64)
	Get()
}
//定义一个实际享元(白色棋子)
type ConcreteFlyweightA struct {
    //它的不变部分
	Color string
	Shape string
	//它的可变部分
	PostX int64
	PostY int64
}
//定义设置不变部分的方法(设置棋子本身)
func (c *ConcreteFlyweightA) Create() {
	c.Color = "黑色"
	c.Shape = "圆形"
}
//定义设置可变部分的方法(棋子的位置)
func (c *ConcreteFlyweightA) Set(x int64, y int64) {
	c.PostX = x
	c.PostY = y
}
//查看方法
func (c *ConcreteFlyweightA) Get() {
	fmt.Printf("%+v\n", c)
}
//定义另一个具体享元(黑子),和第一个类似
type ConcreteFlyweightB struct {
	Color string
	Shape string
	PostX int64
	PostY int64
}
//定义设置不变部分的方法(设置棋子本身)
func (c *ConcreteFlyweightB) Create() {
	c.Color = "白色"
	c.Shape = "圆形"
}
//定义设置可变部分的方法(棋子的位置)
func (c *ConcreteFlyweightB) Set(x int64, y int64) {
	c.PostX = x
	c.PostY = y
}
//查看方法
func (c *ConcreteFlyweightB) Get() {
	fmt.Printf("%+v\n", c)
}
//定义享元工厂,它包含所需的享元且用key标识
type FlyweightFactory struct {
	Flyweights map[int64]Flyweight
}
//定义创建享元的方法。如果找到就返回,找不到就创建
func (f *FlyweightFactory) Get(id int64) (flyweight Flyweight, err error) {
	flyweight, ok := f.Flyweights[id]
	if ok {
		return flyweight, nil
	} else {
		switch id {
		case 1:
			flyweight = &ConcreteFlyweightA{}
			flyweight.Create()
			f.Flyweights[1] = flyweight
			return flyweight, nil
		case 2:
			flyweight = &ConcreteFlyweightB{}
			flyweight.Create()
			f.Flyweights[2] = flyweight
			return flyweight, nil
		default:
			errors.New("id无效")
			return nil, err
		}
	}
}

func main() {
    //实例化一个享元工厂
	flyweightFactory := FlyweightFactory{
		Flyweights: make(map[int64]Flyweight),
	}
	fmt.Println("=========黑棋落第一个子=========")
	//实例化第一个黑子,因为享元工厂中没有复合条件的棋子,因此会创建一个享元返回
	flyweight001, err := flyweightFactory.Get(1)
	if err != nil {
		return
	}
	//设置该棋子的位置
	flyweight001.Set(3, 3)
	//查看结果
	flyweight001.Get()

	fmt.Println("=========白棋落第一个子=========")
	//实例化第一个白子,因为享元工厂中没有复合条件的棋子,因此会创建一个享元返回
	flyweight002, err := flyweightFactory.Get(2)
	if err != nil {
		return
	}
	//设置该棋子的位置
	flyweight002.Set(17, 4)
	//查看结果
	flyweight002.Get()

	fmt.Println("=========黑棋落第二个子=========")
	//实例化第二个黑子,此时享元工厂有复合条件的享元,返回查到的结果(但是我们封装到工厂里,用户并不能察觉是创建还是复制)
	flyweight003, err := flyweightFactory.Get(1)
	if err != nil {
		return
	}
	//设置该棋子的位置
	flyweight003.Set(3, 17)
	//查看结果
	flyweight003.Get()
}
  • 输出
=========黑棋落第一个子=========
&{Color:黑色 Shape:圆形 PostX:3 PostY:3} 
=========白棋落第一个子=========
&{Color:白色 Shape:圆形 PostX:17 PostY:4}
=========黑棋落第二个子=========
&{Color:黑色 Shape:圆形 PostX:3 PostY:17}

2.3 类图示例

这里我们的客户端实际是调用了Flyweight接口
当然我们也可以如示例中一样直接调用每一个实际享元

«interface»
Flyweight
+Create()
+Set(x int64, y int64)
+Get()
ConcreteFlyweightA
+Color:string
+Shape:string
+PostX:int64
+PostY:int64
+Create()
+Set(x int64, y int64)
+Get()
ConcreteFlyweightB
+Color:string
+Shape:string
+PostX:int64
+PostY:int64
+Create()
+Set(x int64, y int64)
+Get()
FlyweightFactory
+Flyweights:HashMap
+Get(id int64) (flyweight Flyweight, err error)
Client

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1021902.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023年中秋·国庆节放假通知

放假期间如有业务、技术及其他相关需求,欢迎新老客户前来咨询!放假期间如给您带来不便敬请谅解! 注意事项 1、放假离开公司前须全面清扫所属办公区域的卫生,收拾好桌面、保管好个人办公物品; 2、关闭个人电脑等办公设备的电源&a…

MySQL DDL操作触发Metadata Lock等待,怎么办?5个高效应对策略解析!

大家好,我是小米,一个热衷于技术分享的程序员。上周三,有一位童鞋在 QQ 群里向我请教了一个关于“alter table 触发metadata lock一直等待”的问题,在今天的文章中,我将与大家分享一些关于MySQL数据库DDL操作中触发Met…

再获认可丨聚焦云计算标准和应用大会,畅谈边缘AI的探索实践

2023年9月13日,中国电子技术标准化研究院主办的第十二届云计算标准和应用大会在北京成功召开。本次大会以“标准筑基 数智创新 云端赋能 合作共赢”为主题,汇聚政产学研用各方专家学者,共享和探讨云计算标准化工作的重要进展以及云计算产业发…

实现可观测性平台的技术要点是什么?

文章目录 实现可观测性平台的技术要点是什么?兼容全域信号量所谓全域信号量有哪些?统一采集和上传工具统一的存储后台自由探索和综合使用数据总结 实现可观测性平台的技术要点是什么? 随着可观测性理念的深入人心,可观测性平台已经开始进入了落地阶段…

RecyclerView滑动时添加缩放效果

最近看到一个动画效果,感觉不错,所以动手试一试 我实现的效果 基本上是已经实现了头像无限滚动中itemview也伴随缩放效果 初步实现基本思路: 1、没选择用ViewPager,考虑到特定几张图片的循环显示和扩展我使用recyclerview 2、头…

lv5 嵌入式开发-2 exec函数族

目录 1 进程 – exec函数族 1.1 exec函数族特点 1.2 进程 – execl / execlp使用方法 1.3 进程 – execv / execvp 2 进程 – system 3 exec族要点演示 掌握:exec函数族、system 1 进程 – exec函数族 执行程序,通孔ps -elf发现,父进…

springcloud3 分布式事务-产生原因的模拟1

一 分布式事务 1.1 分布式事务产生条件 分布式事务,就是指不是在单个服务或单个数据库架构下,产生的事务,例如: 1.跨数据源的分布式事务 2.跨服务的分布式事务 3.综合情况 二 案例操作 2.1 原理架构 订单的创建、库存的扣…

1万多关数独逻辑游戏ACCESS\EXCEL数据库

数独盘面是个九宫,每一宫又分为九个小格。在这八十一格中给出一定的已知数字和解题条件,利用逻辑和推理,在其他的空格上填入1-9的数字。使1-9每个数字在每一行、每一列和每一宫中都只出现一次,所以又称“九宫格”。 每一关存储了8…

【树】B树与B+树

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kuan 的首页,持续学…

计算机视觉与深度学习-经典网络解析-VGG-[北邮鲁鹏]

目录标题 VGG参考VGG网络贡献使用尺寸更小的$3 \times 3$卷积串联来获得更大的感受野放弃使用$11 \times 11$和$5 \times 5$这样的大尺寸卷积核深度更深、非线性更强,网络的参数也更少;去掉了AlexNet中的局部响应归一化层(LRN)层。 网络结构主要改进输入…

车辆检测:An Efficient Wide-Range Pseudo-3D Vehicle Detection Using A Single Camera

论文作者:Zhupeng Ye,Yinqi Li,Zejian Yuan 作者单位:Xian Jiaotong University 论文链接:http://arxiv.org/abs/2309.08369v1 项目链接:https://www.youtube.com/watch?v1gk1PmsQ5Q8 内容简介: 1)方…

GE D20 EME 10BASE-T 控制主板模块

GE D20 EME 控制主板模块通常用于工业自动化和控制系统中,特别是在需要网络连接和通信功能的应用领域。以下是一些可能适用于该模块的应用领域: 工业自动化:GE D20 EME 控制主板模块可用于各种工业自动化应用,包括生产线控制、设备…

【前端知识】Three 学习日志(七)—— 动画渲染循环

Three 学习日志(七)—— 动画渲染循环 一、旋转动画 // 渲染函数 function render() {renderer.render(scene, camera); //执行渲染操作mesh.rotateY(0.01);//每次绕y轴旋转0.01弧度requestAnimationFrame(render);//请求再次执行渲染函数render&#…

【LQR】离散代数黎卡提方程的求解,附Matlab/python代码(笔记)

LQR的核心是设计QRN,并求解对应的黎卡提方程 对于连续状态空间方程系统,先求连续LQR后离散 和 先离散后求离散LQR方程 的结果 是不一样的 1.离散代数黎卡提方程 注:LQR算法中含N项 离散系统: 在matlab里有现成的函数dlqr()&…

【C语言】可变参数列表详解

可变参数列表 一、可变参数列表的使用1、可变参数列表的形式2、可变参数列表的提取3、使用演示4、利用可变参数实现一个简单的日志打印功能 二、可变参数列表的原理1、原理的讲解2、原理的证明 一、可变参数列表的使用 1、可变参数列表的形式 有时我们在使用C语言时可能会碰到…

解决RequestParam.value() was empty on parameter 0

在网上查询很多种方式,都解决不了问题,比如: 在RequestParam RequestBody注解 解决办法:在RequestParam中的name加上对应参数 如 : RequestParam( name "name" ) RequestBody也是同理 最后解决的办法,是发现mave…

【Linux】nohub指令--终端退出后命令仍旧执行

文章目录 0、背景1、作用2、语法3、用法演示4、关于2>&1 0、背景 Shell中,执行一个持续进行的指令,会"霸屏",即你想再执行其他指令,要么重开个shell终端,要么退出这个执行。 1、作用 nohub&#x…

vue 把echarts封装成一个方法 并且从后端读取数据 +转换数据格式 =动态echarts 联动echarts表

1.把echarts 在 methods 封装成一个方法mounted 在中调用 折线图 和柱状图 mounted调用下边两个方法 mounted(){//最早获取DOM元素的生命周期函数 挂载完毕console.log(mounted-id , document.getElementById(charts))this.line()this.pie()},methods里边的方法 line() {// …

苹果麻烦了,全球没有消费者愿意接受印度制造的iPhone

据外媒报道指印度制造的iPhone良率只有一半,以至于发出的货被质量工程师打回一半,由此引发欧洲消费者的抗拒,为安抚欧洲消费者,苹果表示欧洲市场的iPhone15将全数由中国制造供应,而印度制造的iPhone将在印度市场销售以…

基于python的urllib 库抓取网站上的图片

最近写了个爬虫实例,有python环境的话就可以直接运行了。 运行效果是这样的: 完整代码如下: import urllib import urllib.request import re import random import time import os #目标网址: imagePath"https://pic.netbian.com&quo…