Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2017
  • 博文数量: 1
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 20
  • 用 户 组: 普通用户
  • 注册时间: 2015-07-07 22:20
文章分类
文章存档

2015年(1)

我的朋友
最近访客

分类: C/C++

2015-07-07 23:18:32

  在程序开发中,有时候很想访问一个类里面所包含的容器对象。可是将容器获取出来访问,可能会让程序阅读性降低或引入一些线程间互斥的问题。举例如下:


点击(此处)折叠或打开

  1. class B
  2. {
  3. public:
  4. B(){}
  5. ~B(){}
  6. };

  7. class A
  8. {
  9. public:
  10. A(){}
  11. ~A(){}

  12. //为了访问列表B而增加接口
  13. const std::list<B>& listB() const {return mListB;}
  14. std::list<B>& listB() {return mListB;}

  15. void lockB() {mLockB.lock();}
  16. void unlockB() {mLockB.unlock();}
  17. protected:
  18. std::list<B> mListB;
  19. ThreadMutex mLockB;//B容器的锁
  20. };

  21. //这样会引入线程的问题,在外部访问时,就需要这样做
  22. A a;
  23. a.lockB();
  24. std::list<B>& rLstB = a.listB();
  25. for(std::list<B>::iterator it = rLstB.begin(); it != rLstB.end(); ++it)
  26. {
  27.     B& rb = (*it);
  28.     //...TODO:其他操作
  29. }
  30. a.unlockB();
从上面例子可以看到,在外部访问a对象的容器B时,需要加锁和解锁操作。如果操作很长,在中途有return跳出函数,那么也必须加上解锁操作。非常麻烦。

我们来思考一下有没有其他较好的方法呢?就个人而言,写程序放首位的应该是阅读性。这种情况,希望封装性好,有两种方式可以实现,一是迭代器,二是访问器。首先来说一下迭代器,我摘录一段代码:

点击(此处)折叠或打开

  1. /*Iterator迭代器抽象类*/
  2.     abstract class Iterator
  3.     {
  4.         public abstract object First();
  5.         public abstract object Next();
  6.         public abstract object CurrentItem();
  7.         public abstract bool IsDone();
  8.     }
  9.     /*Aggregate聚集抽象类*/
  10.     abstract class Aggregate
  11.     {
  12.         public abstract Iterator createIterator();
  13.     }
  14.   
  15.     class ConcreteIterator : Iterator
  16.     {
  17.       
  18.         // 定义了一个具体聚集对象
  19.         private ConcreteAggregate aggregate;
  20.   
  21.         private int current = 0;
  22.       
  23.         // 初始化对象将具体聚集类传入
  24.         public ConcreteIterator(ConcreteAggregate aggregate)
  25.         {
  26.             this.aggregate = aggregate;
  27.         }
  28.   
  29.         // 第一个对象
  30.         public override object First()
  31.         {
  32.             return aggregate[0];
  33.         }
  34.   
  35.         // 得到聚集的下一对象
  36.         public override object Next()
  37.         {
  38.             object ret = null;
  39.             current++;
  40.             if (current < aggregate.Count)
  41.             {
  42.                 ret = aggregate[current];
  43.             }
  44.             return ret;
  45.         }
  46.   
  47.         // 是否到结尾
  48.         public override bool IsDone()
  49.         {
  50.             return current >= aggregate.Count ? true : false;
  51.         }
  52.   
  53.         // 返回当前聚集对象
  54.         public override object CurrentItem()
  55.         {
  56.             return aggregate[current];
  57.         }

我在网络上找了一段迭代器的代码,只取了其中一段,但是可以注意到Next()函数中,ret = aggregate[current]; 通过索引来访问容器的成员,这就变相规定了,支持的容器仅仅是vector而已,对于list,map等容器,访问这个下标就太耗时间了。所以,迭代器仅仅在自己封装的链表中有效,可以直接访问节点指针。而使用标准容器时,这样用效率太低。

个人推荐使用访问器来访问容器的成员,先上代码:


点击(此处)折叠或打开

  1. class B
  2. {
  3. public:
  4. B(){}
  5. ~B(){}
  6. };

  7. class A
  8. {
  9. public:
  10. //访问器类
  11. class BVisitor()
  12. {
  13.     public:
  14.     virtual ~A(){}
  15.     virtual void apply(const B& rb){}
  16. };

  17. public:
  18. A(){}
  19. ~A(){}

  20. void travel(BVisitor& rVisitor)
  21. {
  22.     mLockB.lock();
  23.     for(std::list<B>::iterator it = mListB.begin(); it != mListB.end(); ++it)
  24.     {
  25.         B& rB = (*it);
  26.         rVisitor.apply(rB);
  27.     }
  28.     mLockB.unlock();
  29. }

  30. protected:
  31. std::list<B> mListB;
  32. ThreadMutex mLockB;//B容器的锁
  33. };

  34. //外部访问时
  35. class MyVisitor : public A::BVisitor
  36. {
  37. public:
  38.     MyVisitor(C* pC, int nMode) : mC(pC), mMode(nMode){}

  39.     void apply(const B& rb)
  40.     {
  41.         //仅说明用法
  42.         if(mMode == 2)
  43.         {
  44.             mC->doSth(rb);
  45.         }
  46.         else
  47.         {
  48.             mC->doSth2(rb);
  49.         }
  50.     }
  51. protected:
  52.     C* mC;    //仅说明一下,可以传入一些临时变量
  53.     int mMode;
  54. };

  55. //外部调用时,这样使用
  56. void XXX()
  57. {
  58.     ...
  59.     A a;
  60.     ...
  61.     MyVisirtor mv(&c, 2);
  62.     a.travel(&mv);
  63. }

这样写的好处就是封装性好,很多临时变量也可以方便传递到访问器中,代码也方便阅读。尤其在大工程中,封装性尤为重要。当然仁者见仁,也许还有其他更好的方法,这里就提出一下我自己的观点,大家一起交流共同进步。














阅读(776) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇:没有了

给主人留下些什么吧!~~