分享
 
 
 

a story of 卓玛

王朝other·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

从前,有一个藏族小姑娘,名叫卓玛。家里很穷,靠拾垃圾(Trash)为生。每天早出晚归,辛勤劳动。 卓玛白天只捡两种垃圾,废纸(Paper)和金子(Gold)(哇,没搞错,金子也是垃圾),晚上回家后,便把垃圾分类放置,废纸放进纸箩(PaperBin),金子放进金库(GoldLib)(见过家里有金库的小姑娘去捡垃圾的吗?)。好了,故事讲到这里,暂且打住。干点正事。

进入正题之前,强烈希望读者读过(Think in C++ 2nd Edition Volume 2, Chapter 10 Design Patterns)

And you can download it at http://pcbook.51soft.com

在《 Think in C++》中,作者用OO中的double dispatch方法实现垃圾的分类。

而我用GP方法。

class Trash //垃圾类

{

};

class PaperBin; //垃圾箱(放废纸)

class GoldLib;//垃圾箱(放金子)

class Paper:public Trash //废纸类

{

};

class Gold:public Trash //金子类

{

};

class PaperBin:public vector<Paper>

{

};

class GoldLib:public vector<Gold>

{

};

class Management //小姑娘卓玛是Management的一个实例

{

private:

PaperBin _myPaperBin; //小姑娘卓玛家里的垃圾箱,只有卓玛可以打开

GoldLib _myGoldLib;

};

我们要做的事是把垃圾自动分类。废纸放进纸箩(PaperBin),金子放进金库(GoldLib)

讲一点编程方面的题外话,编程风格(coding style)。个人认为, 编程风格影响代码质量,最终影响产品质量。我的风格是:

1。类名第一个字母大写。如:Trash, Gold。千万别用拼音字母。如:Laji, Jingzhi。拼音字母在程序中的可读性太差。英文不好的朋友可以用金山词霸先翻译一下。

2。定义成员函数或变量时,首先定义为private。

3。私有成员前加下划线。如:_myPaperbin

4。先定义成员变量。后面要讲到为什么。

编程风格还包括很多方面,可惜上面的代码中没有用到。我又不想没有例子泛泛而谈。有兴趣的朋友可以参考<<Windows coding style>> Microsoft Press

讲完编程风格,说几句设计思路的问题。

程序总是从无到有,从毫不相关到相互联系,从简单到复杂,功能由少到多,逐步丰满起来。我来讲讲怎么做。

1。从无到有:先把Requirement中的名词挑出来,建立一个个class。先别管他们之间的关系。在上面的例子里,我们先建几个空类。如:Trash, Paper, Gold, Paperbin, GoldLib. Management。

2。从毫不相关到相互联系:考虑他们之间的关系。如:Paper,Gold 和Trash是继承关系,Management和 PaperBin,GoldLib是拥有关系。

3。考虑每个类的状态(state):也就是定义成员变量。Trash,Paper,Gold 我们还不知道要干什么。定义为空。Management用来管理垃圾箱,所以它有两个成员变量。分别是_myGoldLib,_myPaperBin。

4。考虑他们之间的相互作用。这只需要 把Requirement中的动词挑出来就可以了。在上面的例子里,小卓玛把废纸放进纸箩(PaperBin),金子放进金库(GoldLib)。我们定义一个动作,注意,一个 小卓玛做的动作,放进 , add(Paper,paperBin), add(Gold, GoldLib)。

5。泛化思考:小卓玛作为一个管理人员,事必躬亲当然是好事,但也太累了。我们能否给小卓玛买一台自动垃圾分类机。这样,小卓玛只要放进(垃圾) add(trash) (而不是add(Paper,paperBin), add(Gold, GoldLib) )就可以了。自动垃圾分类机把不同的垃圾放到不同的容器中。这是本章的中心内容,待会再详谈。我这儿讲的是设计思路。好了,我们为Management增加一个成员函数 add(trash)。

Management 看起来象这样:

class Management

{

private:

PaperBin _myPaperBin;

GoldLib _myGoldLib;

public:

template<class T>

void Add(T aTrash);

};

6。细化。也就是说实现 add(trash)。并根据不同的情况,提供最优实现。( 泛泛而谈,没有例子,您可要骂我了。如果您分析过STL中的allocator,您就会知道, allocator可以根据不同的情况(trivial,nontrivial特性(traits)),提供最优的内存管理方案。建义参阅侯捷的大作《STL原码分析》。网上有本书前5章供预览,足够让您了解STL的原理了。没必要去买整本书。兄弟还认为,候捷的中文不太好,古文一样的文法,还不如读E文来的爽快)

GP(Generic Programming,下同)的中心思想是为了实现代码reuse。为了做到代码reuse,一个必要条件是降低类之间的耦合度。每个类只管自己应该管的事(个人自扫门前雪,休管他人瓦上霜(道德品质有问题?))。如:Paper只应该管自己的事, 现在没事,好,歇着(空类)。别象《Think in C++》中的Paper一样,整天琢磨如何把自个儿add到垃圾箱中去(Paper要实现一个add虚函数)。《Think in C++》中的PaperBin也不是东西,您就是一个容器,没事就该歇着,别象妓院的老鸨一样,整天倚在门口,对每个路过的trash说,进来,进来。还把不满意的给踢出去(没钱也敢逛妓院?)(Paperbin也要实现一个add虚函数,并和paper 中的add配合以实现垃圾分类的目的)。您可以看到,《Think in C++》中的PaperBin 和 paper都做了本不该它们做的事。在兄弟的代码中,每个类个干各的事,互不干扰。

好了,原理和方法讲得差不多了。现在要实作了。丑媳妇早晚要见公婆。

定义头文件,没什么好说的

#include<vector>

#include <iostream>

using namespace std;

请大家注意,迄今为止我们都没定义Paper,Gold要干什么。所以,它们都是空的。

又请大家注意 typedef PaperBin aBin; 这句话。它用来告诉它的管理者(Paper 不知道它的管理者是谁,这样可以降低Paper和其管理者之间的耦合度),如果要把Paper存放起来,请放在PaperBin 中。同理, typedef GoldLib aBin; 告诉它的管理者,如果要把Gold存放起来,请放在GoldBin 中。说穿了,这就是Traits技术。

class Trash

{

};

class PaperBin;

class GoldLib;

class Paper:public Trash

{

public:

typedef PaperBin aBin;

};

class Gold:public Trash

{

public:

typedef GoldLib aBin;

};

class PaperBin:public vector<Paper>

{

};

class GoldLib:public vector<Gold>

{

};

下面两个类是本章的难点,它们用来判断两个类型(T,U) 是不是同一个类型。T=U?

如果是,enum中的 exists为 true,否则exists= false

详细说明在C/C++ Users Journal , Generic<Programming>:Mappings between types and values.

template<int v>

struct Int2Type

{

enum{value=v};

};

template<class T, class U>

class Conversion

{

typedef char Small;

struct Big {char dummy[2];

};

static Small Test(U);

static Big Test(...);

static T MakeT();

public:

enum{ exists=(sizeof(Test(MakeT()))==sizeof(Small))};

};

让我们看看小卓玛干了些什么

首先,Management 只提供一个接口,add(trash); add(trash) 通过呼叫_classify()来分类,_classify()呼叫_Add() 把trash放入指定的垃圾箱中

class Management

{

private:

PaperBin _myPaperBin;

GoldLib _myGoldLib;

template<class Trashs, class Bin>

void _classify(Trashs trash, Bin bin)

{

_classify 判断输入的垃圾箱是否和trash所指定的垃圾箱吻合。如是,把trash放入所指定的垃圾箱,如否,什么也不做,返回。

cout<<Conversion<Trashs::aBin ,Bin>::exists<<endl;

_Add(trash,bin,Int2Type<Conversion<Trashs::aBin ,Bin>::exists >());

};

template<class Trash, class Bin>

void _Add(Trash trash, Bin bin,Int2Type<true>)

{

把 trash放入垃圾箱。

bin.push_back(trash);

cout<<"success adding"<<endl;

}

template<class Trash, class Bin>

void _Add(Trash trash, Bin bin,Int2Type<false>)

{

什么也不做,返回。

cout<<"failed adding"<<endl;

}

public:

template<class T>

void Add(T aTrash)

{

把每个 trash放入各个垃圾箱试试,如果找不到合适的垃圾箱,编译会报错。这样可以减少出错的机会。如果用OO方法的话,您只有等到运行时才知道程序错了。

_classify(aTrash,_myPaperBin);

_classify(aTrash,_myGoldLib);

};

};

int main()

{

Management zhuoma;

生成两种垃圾

Paper apaper;

Gold agold;

把垃圾放入垃圾箱

zhuoma.Add(apaper);

zhuoma.Add(agold);

return 0;

}

程序的说明就写到这里。下面,让我们比较一下《Think in C++》中的方法和GP方法。

1。扩充性:小卓玛要增加一个工作,拾废玻璃。我们只要作如下改动:

增加两个类:

class GlassBin;

class Glass

{

public:

typedef GlassBin aBin;

};

class Glassbin:public vector<Glass>

{

};

修改Management:

增加一个成员变量 GlassBin _myGlass;

增加一行到 Add()

template<class T>

void Add(T aTrash)

{

_classify(aTrash,_myPaperBin);

_classify(aTrash,_myGoldLib);

_classify(aTrash,_myGlassBin)

};

保持其他部分不变。爽吧。

反观《Think in C++》,您可以试着增加一个工作,看看有没有这么简单,关键是条理有没有这么清晰。

2。效率:GP方法不用动态联编,没有vtable。所以在时间上和空间上都好过OO方法。

3。安全性:GP方法利用编译器的强大功能,在编译时揪错。比OO在运行时揪错更早地发现问题。防止因测试不足而把bug带入产品。

4。更简单的用户接口:用户要知道的只是Management.Add(trash)。增加新类不会改变 用户接口。

好了,想到的就这么多。不过,故事还没完。我们的小卓玛每周要把垃圾卖到垃圾回收站去。那时,我们还要考虑废纸和废玻璃的价钱,还有金子的汇率(要和银行打交道)。怎么做呢?下回分解(今天我们的代码仍然有效,让大家看看GP扩充代码功能的威力)

说几句废话:

本人基于黑客的基本理念:传播知识,共同提高。作如下申明:

1。您可以在非盈利的情况下,自由复制,修改,传播。

2。请您把这两句废话包含在其中。

另外,有朋友想和我一起续写卓玛的故事,请email给我。bu3bu4@263.net。条件是,您的大作没有分文报酬。

累过的感觉真好。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有