Chinaunix首页 | 论坛 | 博客
  • 博客访问: 367642
  • 博文数量: 38
  • 博客积分: 256
  • 博客等级: 入伍新兵
  • 技术积分: 846
  • 用 户 组: 普通用户
  • 注册时间: 2012-12-14 23:21
文章分类

全部博文(38)

文章存档

2015年(1)

2014年(1)

2013年(28)

2012年(8)

我的朋友

分类: C/C++

2013-03-01 11:48:28

在平常工作中,用过很多设计模式,但是今天我要描述的应该是被我用的最多的,因为它的抽象功能很强大,在很多场合都可以被用上。有趣的是,这种设计模式又有很多种变形,这些变形可以用于不同的平衡策略。下面我们来一一讲解它们。

 

1. Problem(问题)

如果我们想要给某个类加上计数功能,这个功能可以使我们很轻易的知道,这个类当前有多少实例。我想很多人都会知道怎么做:


  1. class myClass{

  2. private:

  3.     static unsigned int mCurrentNum; <==== key: static



  4. public:

  5.     myClass() { ++mCurrentNum; }

  6.     ~myClass(){ --mCurrentNum; }



  7.     static unsigned int howMany() { return mCurrentNum; }

  8. };

嗯,看样子给一个类加上这样的功能还蛮容易的。


如果在一个软件中,你需要给50,甚至上百个类都添加这样的功能,你还愿意这么做吗?哦,no。这个工作量是不可想想的。
 
那我们就要考虑了,有什么办法能把这个功能打包,然后需要这个功能的类,只要通过一种很容易的接口就可以获得这个功能呢?(一个合格的程序员,不仅仅是要把工作完成,而且要漂亮的完成。不为别人,就为我们干这行)
 
注:这里我们忽略拷贝构造和赋值。因为在实际应用中,一般是不会用到他们的。如果需要我们可以添加。
 
2. requirements (需求)

与设计类库一样,我们做这种基础设施的设计,其接口设计必须满足如下规范

a. 易于使用 : 我们的接口必须设计成易于使用,我们内部的复杂度,客户是不关心的。所以我们要把复杂度隐藏起来(对客户)。为什么要这样?这样我们的客户才愿意使用你设计的类库或者基础设施。否则别人肯定会另起炉灶,而拒绝使用你提供的东西。或者在你提供的东西上包装一层。这都不是我们想要的,如果他能包装,我们为什么不提供包装好的东西?

b. 效率: 我们必须考虑空间和时间上的成本。尽量不增加不必要的额外成本。(但这不是最重要的,第一条才是我们最需要优先考虑的)


另外一个需求是,我们必须找到一种语言特性,能够为客户类自动生成一个静态变量,并在构造是自增,析构时自减。下面我们将会看到,有哪些方法可以做到这点。

3. implementation (实现)

1) Solution-1 (方案一)公共继承

继承是很多人,特别是c++初学者最喜欢用的复用方法(我也喜欢用 :)),所以这里把它排在第一位。

如果使用继承,那就意味着我们有一个基类,被不同的类继承时,能为自动生成一个静态变量。什么语言特性可以做到这点?template。对,就是它。下面我们来看看如何实现:


  1. template<class T>
  2. class Counter{
  3. public:
  4.     Counter() { ++count; }
  5.     ~Counter(){ --count; }

  6.     static unsigned int howMany() { return count; }
  7. private:
  8.     static unsigned int count;
  9. };


只要我们为这个类指定一个不同的模板参数,它就会为我们生成一个新的类,这个新类的所有成员都是独立的。

下面让我们来看看,我们是如何使用它的:


  1. class myClass:public Counter<myClass> {

  2. .....

  3. };


就这么简单,只要一个继承就可以了。你如果向你的同事推销这个功能类,我觉得没人有理由拒绝它。如果有一千个类需要这个功能,你这么简单的一个基类,为大家减少的工作量,可想而知。

什么?你问我这个为什么能工作,好吧。我建议你去学习一下C++模板。你也许很奇怪,为什么我的myClass可以继承于一个以我自己为模板参数的基类。呵呵,它就是可以,而且你也看到了,其实这个模板参数并没有什么作用,只是告诉编译器,为我生成一个特别的独立的类,并拷贝这个模板中的所有成员。

好的,到这里,我想很多人会激动,因为他们学了一个新招,跃跃欲试。但是到了现实世界中,我们会碰到很多困扰,比如说如下情况:


  1. class baseClass;

  2. class myClass:public baseClass{
  3. ......
  4. };


如果你把那个counter类用在这个myClass中的时候,肯定会有人质疑你,说:no,我们不可以用多重继承,它会为我们引起麻烦。你会怎么回答?有没有立即感到沮丧?

别,现实和理想是有差距,但是差距并不像我们想象的那么大。你告诉他:我们的基类里面没有任何数据成员,你可以安全的用它,它不会为你带来麻烦的。

如果你的资历比较浅,而别人又用头衔压你,说你不能这么做,不能用多重继承。好吧,那么我们可以考虑如下方法:


  1. class myClass:public baseClass {
  2. public:
  3.     .....
  4.     static unsigned int howMany()
  5.     { return Counter<myClass>::howMany(); }

  6. private:
  7.     ....
  8.     Counter<myClass> mPrivateCounter;
  9. };
 

看,我们也可以用内嵌的方式同使用这个模板类。但是我们需要多写一些代码。如果我们还是想用一行代码解决问题,应该怎么做呢?

下回分解。

 

阅读(1467) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~