zoukankan      html  css  js  c++  java
  • 【转】Solmyr 的小品文系列之四:对象计数(下)

    http://www.cppblog.com/xmli/archive/2009/08/19/93791.html

    ——————————————————————————————————————————————

    (续上期) 
    “空泛的讨论让人厌烦。”,Solmyr 笑容可掬的说道,“不如我们设定一个简单的场景来看看你的计数器怎么使用吧。假设你是暴雪的程序员,要为星际争霸设计程序表示神族的单位,那么最简单的方案是 ——”,Solmyr 停了下来,望向 zero 。 

    zero 松了一口气 —— 这个问题还不算困难。他在脑中整理了一下思路:“神族的单位应该设计为一个基类,然后每种特定的兵种从这个类派生,每个单位就是这样一个类的对象。”想到这里,他飞快的在百板上写下: 

    class ProtossUnit 

        …… 
    }; 

    class Probe : public ProtossUnit 

        …… 
    }; 

    class Zealot : public ProtossUnit 

        …… 
    }; 

    class Dragoon : public ProtossUnit 

        …… 
    }; 

    Solmyr 点了点头,接着说到:“很好。接下来,我们都知道星际争霸里每个单位都是要占用人口的,也就是说我们得确切知道单位个数,很明显,这是一个对象计数的应用。那么我们该怎样利用你刚才实现的计数器呢?” 

    zero 顺手就在白板上写下: 

    class Probe : public ProtossUnit 

        …… 
        Counter<Probe> m_MyCounter; 
    }; 

    class Zeolot : public ProtossUnit 

        …… 
        Counter<Zeolot> m_MyCounter; 
    }; 

    class Dragoon : public ProtossUnit 

        …… 
        Counter<Dragoon> m_MyCounter; 
    }; 

    不对!! 

    zero 心中划过警兆:这感觉太熟悉了!几乎每次惨遭 Solmyr 毒手之前,都有这种感觉!他几乎都可以感受到 Solmyr 正在寻找顺手的东西来砸他。一定有什么地方不对了! 

    回过头来看看自己写下的东西,zero 很快的发现了自己的错误:Counter<Zeolot> 和 Counter<Dragoon> 是不同的类,它们的计数值各自独立,而星际争霸中各兵种占用人口是共享的。 

    “既然是共享的,那么应该加到基类里。”,zero 急急忙忙的擦去了上面两行代码,写下: 

    class ProtossUnit 

        …… 
        Counter<ProtossUnit> m_MyCounter; 
    }; 

    还 …… 还是不对!zero 立刻又发现了问题:不同的兵种可能占用的人口数并不相同,象 Probe 就只占用一个人口,而 Zealot 和 Dragoon 就要占用两个,这 …… 这 …… 

    zero 再度擦去了刚写下的代码,站在白板之前举棋不定。这时 Solmyr 的声音响了起来:“怎么了?有困难吗?”。此时 Solmyr 脸上的笑容显得特别可恶。 

    “不,我只是不清楚星际争霸中的人口是怎样定义的,这个游戏我从来没有玩过。”,zero 试图拖延一点时间。 

    “是吗?昨天我怎么还听到你在讨论‘星际争霸神族战术’?而且刚才你一下子就写出了三个神族兵种的名称,拼写准确。”,Solmyr 轻易的戳破了 zero 的谎言。 

    “……”,zero 不由得懊恼起来。“怎么办?得让它们共享一个计数器,而且每种兵种的计数值必须不一样 …… 对了!”zero 脑中灵光一闪,写下如下代码: 

    class Probe : public ProtossUnit 

        …… 
        Counter<ProtossUnit> m_MyCounter; 
    }; 

    class Zeolot : public ProtossUnit 

        …… 
        Counter<ProtossUnit> m_MyCounter; 
        Counter<ProtossUnit> m_MyCounter; 
    }; 

    class Dragoon : public ProtossUnit 

        …… 
        Counter<ProtossUnit> m_MyCounter; 
        Counter<ProtossUnit> m_MyCounter; 
    }; 

    “Yeah!OK 了!”,zero 高兴的喊道,全然不顾台下带着笑意的目光 —— 这样的有趣场面已经成了公司里的著名娱乐之一。“共享一个计数器的关键是用哪个类别作为模板参数!不一定非得把本身作为模板参数,完全可以用各个兵种共同的基类!” 

    “那计数值不是 1 呢?” 

    “多放几个计数器就行了!” 

    “嗯,还算不错。” 

    zero 很高兴的看到 Solmyr 上前来在白板上打了一个勾,然而喜悦仅仅维持了一瞬间 —— Solmyr 顺手又在勾上打了一个点。 

    “为什么打个点?”,zero 不满的问。 

    “因为你的计数器设计不佳,想象一下 Carrier ,它占 8 个人口,你是不是要在 Carrier 类中写 8 个 Counter 成员?或者声明一个 Counter 的数组?这样的声明清晰吗?易读吗?” 

    “呃 ……” 

    “而且这样使用 Counter 成员变量,需要计数的对象在空间上会付出更大的代价,对于小对象,大小甚至可能翻一倍。” 

    “嗯 ……” 

    “更进一步的说,计数值为 n 的对象,需要构造 n 个 Counter 对象,运行性能也要受影响。” 

    “啊 …… ” 

    “现在你说说看,怎么改进你的计数器,同时不用改动原来的客户代码?” 

    “哦 …… ” 

    zero 陷入了沉思:改进后的计数器应该有指定计数值的能力,这个能力应该是 …… 应该是对应于一个计数器对象而非整个计数器类的,因为共享同一个计数器的类可能计数值不同,也就是说这里需要为计数器类的对象指定一个参数 …… 啊!原来这么简单! 

    “我知道了!答案就是构造函数!”,zero 飞快的把计数器类的定义改为(原来定义请参见上一期): 

    template <class T> 
    class Counter 

    public: 
        Counter(int step) // 改动部分 
        { 
            m_step = step; 
            m_count += m_step; 
        }; 
        ~Counter(){ m_count -= m_step; }; // 改动部分 

        int GetCout(){ return m_count; }; 

    private: 
        static int m_count; 
        int m_step; // 新加部分 
    }; 

    “嗯,不错,不过还有问题。”,Solmyr 一边点头一边说,“这样一来,以前编写的使用 Counter 类的客户代码就不能编译了 —— 它们会报告说构造的时候少了一个参数。” 

    “这好办。”,zero 很快发现了自己漏掉了什么。他把构造函数的定义改为: 

    Counter(int step = 1) 

    “这样一来,以前的客户代码会缺省的得到计数值 1 ,就像以前一样。” 

    “嗯,表现不错,不过 ……” 

    zero 心中一紧。 

    “算了,今天就这样吧。” 

    “Yeah!” 

    “把今天这些讨论整理成详细文档,下班以前交给我” 

    “啊!~~~~” 

    ……………… 

    就这样,再一次的,故事在 zero 的惨叫声中结束了。

  • 相关阅读:
    查看端口有没有被占用
    微信公众号2()
    How to insert a segment of noise to music file
    puppet practice
    Docker Commands
    LempelZiv algorithm realization
    The algorithm of entropy realization
    Java network programmingguessing game
    Deploy Openstack with RDO and Change VNC console to Spice
    puppet overview
  • 原文地址:https://www.cnblogs.com/iammatthew/p/1806963.html
Copyright © 2011-2022 走看看