策略模式+单例模式(go)

news2024/9/29 13:44:43

《设计模式:可复用面向对象软件的基础》

策略允许算法独立于使用它的客户端而变化。
算法可以互相替换,不影响客户端

在这里插入图片描述

  1. 一个类定义多种行为,并且这些行为在这个类操作中以多个条件形式出现。将相关的条件移入它们各自的Strategy类中以替代这些条件语句。
  2. 许多相关类仅仅行为有异,需要用多个行为配置一个类的方法
  3. 需要使用一个算法的不同变体

Strategy策略:定义所有支持的算法的公共接口。
ConcreteStategy具体策略,以Strategy接口实现某具体算法
Contest 上下文:
用一个ConcreteStrategy对象来配置
维护一个对Strategy对象的引用
可定义一个接口让Stategy访问它的数据

客户创建并传递一个具体的策略A给到Context,Context将其转发给Strategy,这样就仅有客户和Context交互

需求
假设现在就要做一个营销,需要用户参与一个活动,然后完成一系列的任务,最后可以得到一些奖励作为回报。活动的奖励包含美团外卖、酒旅和美食等多种品类券,现在需要你帮忙设计一套奖励发放方案

完整案例:
https://tech.meituan.com/2022/03/10/interesting-talk-about-design-patterns.html

例子概括:
美团的奖励的例子,从一开始的多个if到后面彻底删除条件判断
方案1:通过奖励类型进行判断调用什么函数,多个if条件进行判断,不符合开闭原则、迪米特法则
方案2:使用策略模式,抽象一层奖励策略接口,具体的奖励类型作为具体的策略实现这一奖励策略接口,增加一个环境类(内免除不了分支判断),供给奖励服务调用。
降低了耦合度
方案3:单例模式、优化环境类
环境类新增Map注册表,注册所有具体策略,传入奖励类型,就可以通过map匹配到具体策略。
使用饿汉式单例模式

package main

import (
	"fmt"
)

// Strategy 策略接口
type Strategy interface {
	issue()
}

// 策略上下文,用于管理策略的注册和获取--------------
type StrategyContext struct {
	registerMap map[string]Strategy
}

// 注册策略
func (c *StrategyContext) RegisterStrategy(rewardType string, strategy Strategy) {
	if c.registerMap == nil {
		c.registerMap = make(map[string]Strategy)
	}
	c.registerMap[rewardType] = strategy
}

// 获取策略
func (c *StrategyContext) GetStrategy(rewardType string) Strategy {
	return c.registerMap[rewardType]
}

//--------------

// 单例外卖策略 --------------
type WaimaiService struct{}

func (w *WaimaiService) Issue() {
	fmt.Println("Waimai Reward")
}

type WaimaiStrategy struct {
	waimaiService WaimaiService
}

var instanceWaimai *WaimaiStrategy

// 获取单例
func GetInstanceWaimai() *WaimaiStrategy {
	if instanceWaimai == nil {
		instanceWaimai = &WaimaiStrategy{waimaiService: WaimaiService{}}
	}
	return instanceWaimai
}

// 实现接口方法(go:一个类型只需要实现接口声明的所有方法即可被认定为实现了这个接口)
func (w *WaimaiStrategy) issue() {
	w.waimaiService.Issue()
}

// 单例酒店策略-----------

type HotelStrategy struct {
	hotelService HotelService
}
type HotelService struct{}

func (w *HotelService) Issue() {
	fmt.Println("Hotel Reward")
}

var instanceHotel *HotelStrategy

// 获取单例

func GetInstanceHotel() *HotelStrategy {
	if instanceHotel == nil {
		instanceHotel = &HotelStrategy{hotelService: HotelService{}}
	}
	return instanceHotel
}

// 实现接口方法

func (h *HotelStrategy) issue() {
	h.hotelService.Issue()
}

// 单例美食策略-----------
type FoodStrategy struct {
	foodService FoodService
}
type FoodService struct{}

func (w *FoodService) Issue() {
	fmt.Println("Food Reward")
}

var instanceFood *FoodStrategy

// 获取单例
func GetInstanceFood() *FoodStrategy {
	if instanceFood == nil {
		instanceFood = &FoodStrategy{foodService: FoodService{}}
	}
	return instanceFood
}

// 实现接口方法
func (f *FoodStrategy) issue() {
	f.foodService.Issue()
}

// 注册所有策略
func main() {
	// go只有init进行初始化,但是这样我觉得破坏了开闭原则,所以这个操作放在main
	// 但是这样每次用之前都要注册一次,不实际,实际使用得在init统一注册
	context := &StrategyContext{}
	//外卖策略注册,调用
	waimaiInstance := GetInstanceWaimai()
	context.RegisterStrategy(
		"waimai",
		waimaiInstance,
	)
	context.GetStrategy("waimai").issue()
	//酒店
	hotelInstance := GetInstanceHotel()
	context.RegisterStrategy(
		"hotel",
		hotelInstance,
	)
	context.GetStrategy("hotel").issue()
	//美食
	foodInstance := GetInstanceFood()
	context.RegisterStrategy(
		"food",
		foodInstance,
	)
	context.GetStrategy("food").issue()

}

//Waimai Reward
//Hotel Reward
//Food Reward

不够满意,go的初始化操作只有init,整个包的初始化都要统一放在一个函数,没有像python的__init__这样一个类自己有一个自执行函数,这样修改go的init函数貌似也破坏了开闭原则,所以只想到放在main

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

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

相关文章

Tomcat 的maxConnections、maxThreads、acceptCount 之间的关系

1. 在springboot 项目配置方式 server:port: 8081servlet:context-path: "/account"tomcat:threads:max: 200min-spare: 10max-connections: 8192accept-count: 100connection-timeout: 10000min-spare :最小线程数 最小工作空闲线程数,默认1…

ChatGPT 自定义提示词模板提升使用效率

相关文章推荐: 《提问的艺术:如何通过提示词让 ChatGPT 更准确地理解你的问题?》 《这些免费插件,让你的 ChatGPT 效率爆炸》 一、背景 现在 ChatGPT 异常火爆,很多人都在体验甚至购买 ChatGPT Plus。 现在使用 ChatG…

ProtoBuf之启航

"How do we do we do go refarming~" 如何理解序列化和反序列化? 序列化: 把 对象 转换为 字节序列 的过程 称为对象的序列化。 反序列化: 把 字节序列 恢复为 对象 的过程 称为对象的反序列化。 这两对反义词从概念上来说并不难理解,但是为什么有事没…

Xcode 14.3 和 iOS 16.4 为 SwiftUI 带来了哪些新的功能?

0. 概览 今年年初,Apple 推出了最新的 Xcode 14.3 以及对应的 iOS 16.4 。 与此同时,它们对目前最新的 SwiftUI 4.0 也添加了一些新功能: sheet 弹窗后部视图(Interact with a view Behind a sheet)可交互&#xff…

高级树结构

二叉排序树 左子树中所有结点的值,均小于其根结点的值。 右子树中所有结点的值,均大于其根结点的值。 二叉搜索树的子树也是二叉搜索树。 注意: 1.二叉查找树不能插入重复元素 2.中序遍历是一个递增的数列 3.高度越小查询效率越高 二叉排序…

RK3568平台开发系列讲解(驱动基础篇)RK 看门狗的使用

🚀返回专栏总目录 文章目录 一、简介二、DTS配置三、使用沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇将对RK 看门狗的使用进行学习。 文章目录 一、简介二、DTS配置三、使用一、简介 看门狗(watchdog)是一个定时器,启动之后会开始计时。系统或者软件需要…

一个非常sb的报错……idea创建项目初始化失败……

今天在用idea创建项目时报错项目初始化失败; 一开始以为是配置原因,但后面尝试创建空项目都失败…… 觉得可能跟版本什么的无关,尝试重启、更新系统后,试着以管理员身份运行idea,问题解决了……………… 如果有报错信…

C语言——结构体初阶

哈喽,大家好,今天我们来学习C语言中的结构体,今天主要学习初阶结构体,后期我们将继续学习结构体进阶。 目录 1.结构体类型的声明 1.1 结构体的基础知识 1.2 结构的声明 1.3 结构成员的类型 1.4 结构体变量的定义和初始化 2. …

Cannot resolve plugin com.spotify:docker-maven-plugin:1.2.2 not found

问题 遇到这个错误是按照ruoyi-clou-plus把插件复制过来的,开始没有版本号,一直爆红,自己随便试了几个版本号,还是提示Cannot resolve plugin com.spotify:docker-maven-plugin not found 过程分析 百度了很多都说在settings.xml中加上 …

Tomcat安装与使用

Tomcat 是HTTP服务器,用于使用HTTP协议。 1、下载Tomcat 下载链接:https://tomcat.apache.org/ 进入官网后,根据自己想要下载的版本进行下载,我这里选择下载的版本是Tomcat 8. 点击选择自己想要下载的对应版本,下载Z…

基于Kruskal和Prim的最小生成树算法[matlab版本]

Kruskal算法 ------------------------------------ Kruskal算法为顺序取边的算法,复杂度与边的数量m有关, 为o(m log2 m).步骤如下: (1)初始化:最小生成树的边集A = ∅,对于图G中每个节点v ∈ V,生成 一个仅包含该节点的子树; (2)将图G中所有的边按照非降序方式排列; (…

YOLOv5、YOLOv7独家原创改进:独家首发最新EfficiCLNMS改进点,改进有效可以直接当做自己的原创改进点来写,新的增强预测帧

💡该教程为属于《芒果书》📚系列,包含大量的原创首发改进方式, 所有文章都是全网首发原创改进内容🚀 💡本篇文章为YOLOv5、YOLOv7改进:独家首发最新EfficiCL-NMS改进点,新的增强预测帧率。 💡对自己数据集改进有效的话,可以直接当做自己的原创改进点来写!!!改…

Trace32 SRST和TRST、system.attach 和 system.up的区别

目录 TRST-Resets the JTAG TAP controller and the CPU internal debug logic SRST- Resets the CPU core and peripherals SYStem.Mode Down SYStem.Mode Nodebug SYStem.Mode Prepare SYStem.Mode Go SYStem.Mode Attach SYStem.Mode StandBy SYStem.Mode Up 下图为…

HLS入门-LED闪烁仿真

什么是HLS HLS(High-Level Synthesis)是一种硬件描述语言编程技术,它可以将高级语言(如C/C)转换为硬件描述语言(如VHDL或Verilog),以便将其用于FPGA设计中。 HLS有什么核心技术&am…

《嵌入式系统开发实践》实验二 进程与线程

一、 实验目的 了解Linux中进程和线程的概念; 了解多线程程序的基本原理; 了解pthread库; 掌握用system、exec函数族、fork函数创建进程; 掌握使用pthread库中的函数编写多线程程序。 二、 实验任务与要求 应用fork函数创建子进…

行云流水| CI 3.0 云原生构建全新上线

研发过程中,如何直观且准确地获悉代码提交后的质量状态? 引入持续集成,可以自动化的对代码进行代码检查、单元测试、编译构建、甚至部署与发布,大幅提升开发人员的效率。 腾讯云 CODING 推出 CI 3.0 ——云原生构建,是…

LabVIEW:强大的图形化编程工具

LabVIEW(Laboratory Virtual Instrument Engineering Workbench)是由美国国家仪器公司(National Instruments)开发的一种直观而强大的工程软件,被广泛应用于各个领域的工程师和科学家之中。 与传统的编程语言相比&…

打包后定义配置文件针对.vue和.js文件不同配置方法

条件:需要打包后形成config文件,在打包后改变此配置文件即可改变配置,如api地址,vue中方法参数和条件。 (1)首先config文件要在public文件中建立,webpack打包后config文件才会出现在打包的dist文…

SpringMVC第四阶段:Controller中如何接收请求参数

Controller中如何接收请求参数 1、原生API参数类型 1.1、HttpServletRequest类 只需要在Controller的目标方法中, 直接写上HttpServletRequest对象即可获取 原生API的 request对象实例。 RequestMapping(value "/p1") public String param1(HttpServletRequest …

( 动态规划) 1035. 不相交的线 ——【Leetcode每日一题】

❓1035. 不相交的线 难度:中等 在两条独立的水平线上按给定的顺序写下 nums1 和 nums2 中的整数。 现在,可以绘制一些连接两个数字 nums1[i] 和 nums2[j] 的直线,这些直线需要同时满足满足: nums1[i] nums2[j]且绘制的直线不…