欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 美景 > 这是啥设计模式-单例模式

这是啥设计模式-单例模式

2025/9/20 17:40:29 来源:https://blog.csdn.net/he_wen_jie/article/details/141304741  浏览:    关键词:这是啥设计模式-单例模式

召回算法中有一个叫做I2I的召回方式,给定一个Item,返回跟这个Item相似的topK个Item,这种相似关系一般在离线就计算好了,以KV的方式存储下来

<item1, [item2, item3,item4]>
<item2, [item1, item5,item6]>
...

我们使用的时候也加载成kv的格式就可以了

1. 基础实现

我们要提供这样一个数据,同样需要定义一个接口

using KvPair = std::unordered_map<std::string, std::vector<std::string>>;
class Kv{
public:Kv() = default;void update(const std::string& kvPath) {auto kv = std::make_shared<KvPair>();kv->emplace("item1", std::vector<std::string>{"item1", "item2", "item3"});kv->emplace("item2", std::vector<std::string>{"item1", "item4"});kv->emplace("item3", std::vector<std::string>{"item1"});{// 使用 lock_guard 锁定互斥锁std::lock_guard<std::mutex> lock(mtx);m_kv.swap(kv);}}std::vector<std::string> getTopK(const std::string& item) {auto iter = m_kv->find(item);if(iter != m_kv->end()) {return iter->second;}return std::vector<std::string>();}~Kv() = default;
private:std::shared_ptr<KvPair> m_kv = std::make_shared<KvPair>();// 创建一个互斥锁std::mutex mtx;
}

我们实现了两个方法,一个是数据更新的方法,一个是获取TopK的方法。客户端调用也非常的简单

auto kv = new Kv();
Kv->update('kv.pb');
auto items = Kv->getItems("item1");

2. 多处调用

现在有好几个地方都会调用这份kv数据,我们简单实现一下,第一个是test1.cpp文件

// test1.cpp
void test1() {auto kv = new Kv();Kv->update('kv.pb');auto items = Kv->getItems("item1");
}

第二个地方是test2.cpp文件

// test2.cpp
void test2() {auto kv = new Kv();Kv->update('kv.pb');auto items = Kv->getItems("item1");
}

这么实现的问题非常的明显,就是每个地方调用都需要加载一次数据,但是这份数据不会发生变化,谁调用都是一样的。

3. 单例模式

一个简单的想法就是让这个类对象只有一个,首先构造函数不能暴露出来,不然就可以定义多个对象了

class Kv{
private:// 构造函数和析构函数都定义为private,防止被外部调用Kv() = default;~Kv() = default;// 将其拷贝构造和赋值构造成为私有函数, 禁止外部拷贝和赋值Kv(const Kv &kv) = delete;const Kv &operator=(const Kv &kv) = delete;
public:// 类方法,类直接调用static Kv *GetInstance();
}

问题是构造函数都变成私有的了,该如何实例化这个对象呢?我们可以定义一个函数来代替构造函数,在这个函数里面我们设置一个标识符,表示这个对象是否已经初始化过了,如果初始化过了,就返回之前构造出来的对象,否则就进行构造初始化

Kv* Kv::kvInstance{nullptr};
std::mutex Kv::mutexKvInstance;
Kv* Kv::GetInstance()
{std::lock_guard<std::mutex> lock(mutexKvInstance);if (kvInstance== nullptr) // 如果是nullptr说明还没有被初始化过{kvInstance= new Kv();}return kvInstance; // 返回唯一的对象
}

还有一种更有有趣的实现方法,极力推荐

// 注意:不能返回指针的引用,否则存在外部被修改的风险!
Kv& Kv::GetInstance()
{/*** 局部静态特性的方式实现单实例。静态局部变量只在当前函数内有效,其他函数无法访问。* 静态局部变量只在第一次被调用的时候初始化,也存储在静态存储区,生命周期从第一次被初始化起至程序结束止。*/static Kv kv;return kv;
}

4. 单例模式python

import threading
class Singleton(object):_instance_lock = threading.Lock()def __init__(self):pass@classmethoddef instance(cls, *args, **kwargs):with Singleton._instance_lock:if not hasattr(Singleton, "_instance"):Singleton._instance = Singleton(*args, **kwargs)return Singleton._instance

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com