STL+Template打造“万能”数据模板

 在使用C++进行日常开发过程中,基本都会使用STL或者是类似的基础库,以便提高开发效率。STL库提供的那些数据结构实在是很好用,如map、list、vector这些能轻松方便的在工程中直接使用,如果是不含指针的常用类型基本STL就已经实现了“万能”的数据模板,除了线程安全之外。本篇就是讲述利用STL库中那些现有的诸如map、list、vector数据结构,并且模仿他们的实现方式,来打造一个线程安全的“万能”数据模板。

一、为什么要打造“万能”的数据模板。  

为什么已经有了STL,还需要再打造一个呢?原因大致有以下几点:

1. 线程安全问题。

由于STL实现并不是线程安全的,所以在工程中使用的时候,如果是多线程环境,那么需要自行保证线程安全性。如果一个类数据变量较多,那么类代码中就会有较多线程安全方面比较类似的数据变量访问代码,与类自身的业务实现并没太大关系,既影响代码阅读也增加维护出错可能,如果把这部分相似度较高的代码,模仿STL的实现方式利用Template进行封装,既能保持“万能”数据特性,又在此基础上添加了线程安全,那就接近完美了。

2. 缩减代码,便于维护。

其实这个原因在上述原因解决过程中已经体现,这两个原因最后都殊途同归,单独再复述是为了强调重要性。STL中常用数据结构的访问代码包括迭代器的使用代码,都非常类似,很容易就能封装,封装之后代码的缩减是显而易见的,这样能将于业务无关的代码从业务代码中剥离出来,便于代码阅读保持思维连贯性。同时对于一些数据变量较多的类,还可能防止不小心造成的死锁,减少出错的可能,提高代码的维护效率。

3. 高效开发,风格统一。

使用了Template关键字,又加入了线程安全的特性。几乎保持了原有STL的“万能”数据结构特征,可以作为基础类库使用在各个工程中,如果是一个规模较为庞大的系统,包含多个工程,使用这样的数据模板无疑能带来很多好处。如高效的开发速度,代码风格的统一性,代码的安全性,等等都可以得到加强和保障。使用者只需要定义自己关心的数据结构,及附加在该数据结构中的一些为了扩展而添加的方法,既能达到目的。可以想象工程中,没有自定义的数据锁,基本可以杜绝死锁可能。数据变量定义统一,访问统一,风格也统一,后续的维护人员维护代码时,也将大大减少工作量。

二、如何进行“万能”数据模板的封装。

1. 模仿STL的实现,使用c++的Template将需要的STL数据结构封装进模板内,日常开发过程中,一般常用是map,声明map数据变量设为私有,key、vaule均由外部自定义即可。

2. 将互斥锁封装进模板内,有了互斥锁,就有了多线程同步的基本实现工具,在代码内根据应用场景添加互斥锁使用即可达到多线程同步目的,互斥进行数据结构访问。

3. 对外提供相应接口,并在代码实现时根据情况使用互斥锁,以便保证多线程安全。

三、封装原则,及简单说明。

1. 基本访问接口。一般来说对于数据模板,仅需数据相关的增、删、查三类接口既能满足大多数应用场景。而该类接口STL已经提供了实现,我们在封装实现中仅需要加上互斥锁保证多线程安全,基本就能实现。

2. 修改数据接口。一般来说有了增、删、查就够用,但常用数据还需要有修改数据功能,如果是常用的整体数据更新,那么很好实现,直接查到数据节点替换即可,但是某些特殊情况可能不需要或者是不能进行全量替换,这个时候就需要提供一个特殊接口来实现部分数据更新的功能,如果情况更加复杂一点,数据更新涉及到多个字段,有各种数据更新组合,这个时候就需要设计接口时考虑更加周全,俗话千个师傅千个法,本篇给出我在项目中设计的接口,抛砖引玉,如读者有更好的建议,请留言告知。这样的接口,需要达到能分辨更新类型,且需要考虑复用性能可扩展性,这样的话,需要把数据更新的实现,交由用户来实现,模板内只提供方法调用,这么设计就能保持数据模板的相对固化且具有较高灵活性,大致的接口设计如下:

boot update(K & key,int type, V & value)

{

        //互斥锁实现...

        iterator it = info.find(key);

        if(it != info.end())

        {

              it->second.update(type, value);//本处调用外部数据结构定义的方法更新数据

              return true;

        }

        return false;

}

接口说明:本接口参数较为直观,包含查找数据需要的key,更新类型type,和更新数据value,本接口调用外部定义的update方法进行数据更新的实现,只有调用者才知道更新类型和更新的数据字段,达到了模板代码相对固化和保持较高灵活性目的。

3. 特殊接口。在某些特殊情况下,可能需要暴露被封装的数据成员给外部使用,虽然这个需求违反封装前提和原则,同时也增加了死锁和其他问题的风险,但是在某些特殊情况下必须提供这类特殊接口才能保证逻辑的正确性。本篇从实用出发,给出相应的解决方案,以供各位在遇到该类情况下参考使用,但是尽量少用该类接口,如使用时需要万分谨慎不要造成死锁。

特殊接口核心功能就是暴露被封装的数据锁,和数据变量,以便外部调用者来决定何时使用,如何使用被封装对象,那么接口设计就相对简单,只要把被封装私有对象通过接口暴露出去即能达到目的。

//处理函数指针

typedef    void(*Fun)(Lock * plock, std::map<K, V> & info, void * ptr);

接口设计大致为:OutDeal(FUN DealProcess, void * ptr);

接口说明:DealProcess由外部调用者传入的处理函数指针,由该函数指针提供的参数接口把被封装的数据锁和数据对象暴露给外部。同时考虑到数据处理调用者数据处理问题,添加void *ptr参数,将调用者本身传入,在函数处理时方便数据制作。

再次声明:本方法由于暴露了被封装对象,已经违反了封装原则,所以慎重使用。

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值