前一段时间负责负责论坛的迁移工作,对其架构进行了简单的整理。前几天看到有人说
discuz的介绍很少,因此整理了一下,发布出来。
       也是第一次发表文章,大侠们手下留情。
  

 

Discuz整体架构如下图所示:

 

 

横向表示 同一层次中涉及的各个模块(项目)

纵向表示 不同层次之间模块的关系,某些关系是如何在各层次中传递(穿越)

         Discuz架构上采用了比较流行的三层架构,即表现层,业务逻辑层,数据访问层来进行设计,并结合自己的情况进行了特殊处理。

表现层:

         表现层即为上图中蓝色虚线表示,主要包括:WebServicesUIControl。各项目主要功能为:

UI 定义各种页面基类,提供Ajax访问访问接口。

Control存放Discuz用到的自定义服务器端控件。

Services提供外部访问接口。

 

         Discuz引入了一种模板引擎的机制,来实现表现层的多样化。

主要设计思想为:针对设计人员,提供纯静态页面,并提供了一套约定的语法和标签(具体位置在:templates)。模板制作完成后,要进行模板导入,此时discuz会将静态模板进行解析将其转换成 aspx页面,然后放到aspx/1..n下。如果你打开这下面的文件,会发现前端只是一个字符串拼接的过程。要进行的逻辑判断,都放到了后台代码中。后台代码只有一份,所有的 aspx模板引用同一个后台处理类。由此实现web表现的多样化

 

当用户进行页面浏览时,首先确定显示哪个模板,然后采用地址重写技术,将其转移到实际的处理文件。在web.config配置为

 


 

可见Discuz对所有的请求进行了控制,其代码如下 (以Index.aspx为例):

 

 

 

 




首先程序会先查找
Cookie,找到TemplateId,然后重定向到相应的模板文件。

综上所述:模板+重定向实现了表现层的多样化。

 

业务逻辑层:

         业务逻辑,顾名思义就是处理与业务相关的代码。Discuz采用的也是中小型项目的常用的“贫血模式”,即在业务逻辑层只是进行实体的获取,转发和赋值,几乎没有业务操作。

本该封装在此层的业务代码进行了分散,一部分前移至表现层(比如发帖时的加分操作,附件处理),一部分后移到了存储过程(比如发帖后更新我的发帖列表)。

注:关于贫血模式的论述详见 Martin Fowler的相关著作<企业应用架构模式>      

 

         在业务层,使用了Discuz缓存。主要是更改了存储体,将其存储在xml中(为啥这么喜欢用xml呢,印象中它是很慢的),调用方法和通常情况下几乎无差别。

个人感觉其业务逻辑层是项目中设计最失败的地方。拿发帖举例,如果我进行设计,我的方案可能会是这样:

时间关系,有时间再写一篇文章。

 

顺便说一句:如果要进行Discuz的整合,主要调用的就是此层的代码。

主要项目为:

Discuz.Forum

Discuz.Space

 

        

数据访问层:

 

Discuz基于商业考虑和版本限制等因素,迄今为止已有多种数据源:accessmysqlsqlserver等。为了实现三种数据库的接口统一,此处使用了接口和抽象类进行规范。

其类库结构如下(调用方以Post为例)

 

 

 


各个数据库中的
PostManage都使用DbHelper进行通用数据库的访问。DbHelper本身并没有指定具体的数据库链接类型,参数类型,而是使用.Net自带的抽象类DbProviderFactory来创建。具体数据库的加载要等其静态属性Provider,Factory调用时,读取配置文件,以反射形式进行初始化。

代码如下:

 

 

 

通过此种形式,可以实现各种数据接口的调用的统一,同时方便数据库类型的拓展。比如要加入Oracle的支持,只需要继承IDbProvider实现OracleProvider,新的PostManage继承IDataProvider重写部分方法即可。

而业务层(Posts)的调用通过IDataProvider接口来进行统一,避免了和数据库类型的耦合,可以在不改变业务层,表现层的代码基础上实现数据库之间的迁移。这正是大型项目所需要的,以接口来实现层与层之间的通讯,将更多的可变因素,扩充点实现配置化。

 

 

其他子模块的介绍

 

1.       配置

对配置的管理,小型项目可以直接使用web.config,中大型项目一般使用自己的配置解决方案。原因是:

1. 中大型项目配置文件过多,直接使用web.config来会造成其体积过大

2. web.config直接使用字符串进行读取不方便,

 试着比较一下:

 ConfigurationManager.AppSetting[“SiteName”];

 SiteInfo.Name

3. 每次都需要进行类型转换

 

 

 Discuz实现了自己的配置类,其类结构如下(Email为例)

 


IConfigInfo为空接口,没有定义任何方法,主要是方便DefaultConfigFileManager传递,方便以后扩充。对配置文件的解析也没有使用.Net自带的接口,而是重新定义了接口,同时使用了xml反序列化实现配置文件的加载和类型转换。

代码见: DefaultConfigFileManager.DeserializeInfo

 





比较疑惑的是这个项目中某些类给出了实现,却没有发现调用。可能是兼容或者扩充问题留下的,谁对这方面了解的,也可以跟帖说下。

这些类有:ConfigProviderIConfigFileManager

 

2.       数据库表的设计

数据库设计中有两个引人注意的地方:

1.       主题表分离

 

如果由我们来设计主题表和回帖表,通常的做法是如下。

 


 

 

这样在获取主题列表时,直接使用分页算法提取Topics;查看某一帖子时,还需要对TopicsPosts进行jion链接。

此种设计的缺陷为:

1.       Topics表存储Content的内容,其体积将会很大,对大体积表进行分页,性能很慢。

2.       显示Posts内容时将进行join操作,损耗性能

Discuz的做法是进行如下设计。

 




 

Topics里的Content拆分到Posts中去,同时Topics的主题帖也作为回帖放置到Posts里面,这样就解决了上面我们提出的两个问题。这是典型的违反数据库设计范式以换取更好性能的示例。

 

2 Posts表进行水平拆分

         原来以为每一百万帖子,discuz会自动进行拆分,后来发现在discuz后台能够进行设置,手动进行分表,discuz建议每30-50万帖子进行一次拆分。

         进行拆分后,每个表的体积将会减少,保证了查询的效率

 

 

Discuz的整体架构还有很多其他值得细说的地方,例如插件、扩展等,这些需要感兴趣的人自己一一去研究,在此就不多讲了.

posted @ 2009-05-24 14:18 awp110 阅读(195) 评论(1) 编辑

缘起:以前写过一篇文章《Discuz!NT持续集成实战》介绍CruiseControl.net 来做Discuz!NT项目的持续集成 。最近喜欢上了 Powershell ,由于本人向来懒惰,遂将日常工作中一些琐碎的,重复的事情用 powershell 来做了。为此某不才,读了 PowerShell 自带的 《GettingStarted》和《UserGuide》 ,基本的东西也就差不多了。在实践的过程中也曾被一些小问题卡住,在ps自带的文档中没有发现解决办法。幸而得到高人相助,一句话道破天机。(悄悄说:这位高人最近酝酿一件关于ps的作品)

 

 

废话少说,上代码:

Code dnt_publish.ps1

 

下面是一些功能函数 :

Code function.ps1

这里需要注意的是 dnt_publish.ps1文件中 引入 function.ps1文件的方法:文件名前用了两个点,而且两个点中间需要有空格

 

闲言碎语:不才初步体验了PowerShell 一下,感觉很不错哦,像粘合剂一样 把一些小工具 ,WMI .Net Framework 等联系起来 组成超级强大的武器。 语法么还是稍稍感觉有些怪,不太舒服,不过习惯就好了。 另外如果VS能支持 PowerShell 就好了,感觉 PowerShellPlus 用起来还是稍稍不爽。自从写了这个脚本,一切只需轻轻的点一下鼠标,真个过程就自动ok了 (过程: svn check out -> MSBuild 编译解决方案 -> 上传到FTP服务器) 。当然 结合前天代震军同学翻译的文章

http://www.cnblogs.com/daizhj/archive/2008/12/22/1352019.html  ,就可以实现整个的打包发布流程咯。

行文仓促,如有谬误 ,还请指正

编辑器不好用,上面的代码可能有问题, 提供源代码下载:http://files.cnblogs.com/zjneter/dnt_publish.rar

posted @ 2009-05-24 14:17 awp110 阅读(79) 评论(0) 编辑

来当前公司2个多月,因为公司需要用到开源Discuz!nt进行二次开发,所以自己有机会学习Discuz!nt一些架构,设计模式,自定义控件,模板机制等技术,除了看开源源码外,当然主要还是要参考代震军BLOG写的一些文章,这里非常感谢代震军BLOG

这里本文主要做些链接方便自己查找方便

     控件类:

    Discuz!NT控件剖析 之 Button [原创: 附源码] 
    Discuz!NT控件剖析 之 TextBox [原创: 附源码]
    Discuz!NT控件剖析 之 ColorPicker(颜色拾取) 和Calendar(日历) [原创: 附源码]
    Discuz!NT控件剖析 之 Tab 属性页 [原创: 附源码] 
    Discuz!NT控件剖析 之 DataGrid(数据列表) [原创: 附源码] 
    Discuz!NT控件剖析 之 左侧导航控件 [原创: 附源码]
 

    架构类:

    Discuz!NT 缓存设计简析 [原创]
    Discuz!NT 聚合功能页面程序架构(重构到Facade与Observer模式)
    Discuz!NT 中的数据库链接类(抽象类工厂模式)
    Discuz!NT之配置文件类[discuz.config]
    Discuz!NT 模板机制分析

    插件类:
    Discuz!NT 邮件插件机制分析

其余文章我找到后再慢慢添加。。。

Discuz!NT前台模型架构(MVC)

DiscuzNT 实体项目(Entity) 简析

Discuz!NT 的URL地址重写(URLRewrite)

Discuz!NT 在线用户功能简介

Discuz!NT中远程附件的功能实现[FTP协议]

DiscuzNT 商品交易插件设计之用例模型

DiscuzNT 交易插件设计之商品添加,编辑和删除(CUD)

DiscuzNT 商品交易插件设计之[线下交易流程]

DiscuzNT 商品交易插件设计之[线上交易]---支付宝

DiscuzNT 商品交易插件设计之[线上交易]---业务流程

DiscuzNT商品交易插件设计之[信用机制]

posted @ 2009-05-24 14:16 awp110 阅读(597) 评论(1) 编辑
用户权限表    cdb_access    会员的UID编号    uid
        版块的ID号    fid
        是否允许查看贴子    allowview
        是否允许发贴    allowpost
        是否允许回复    allowreply
        是否允许下载附件    allowgetattach
        是否允许上传附件    allowpostattach
        管理员    adminuser
        时间    dateline
            
活动帖    cdb_activities    标题id    tid
        发起人id    uid
        活动花费    cost
        活动开始时间    starttimefrom
        活动结束时间    starttimeto
        活动地址    place
        活动类别    class
        性别限制    gender
        需要人数    number
        征集截止期    expiration
            
活动申请    cdb_activityapplies    申请帖id    applyid
        标题id    tid
        用户名    username
        用户id    uid
        留言    message
        验证状态    verified
        时间    dateline
        支付方式    payment
        联系方式    contact

管理动作表    cdb_adminactions    管理组组id    admingid
        禁止行为    disabledactions

管理员定制    cdb_admincustom    id    id
        标题    title
        url    url
        类别    sort
        显示次序    displayorder
        动作    clicks
        用户id    uid
        时间    dateline

管理组数据表    cdb_admingroups    管理组的ID    admingid
        编辑帖子权限    alloweditpost
        编辑投票权限    alloweditpoll
        置顶帖子权限    allowstickthread
        编辑帖子权限    allowmodpost
        删除帖子权限    allowdelpost
        批量删帖权限    allowmassprune
        强制退款权限    allowrefund
        过滤词语设置权限    allowcensorword
        查看ip权限    allowviewip
        禁止ip权限    allowbanip
        编辑用户权限    allowedituser
        审核用户权限    allowmoduser
        禁止用户权限    allowbanuser
        发表公告权限    allowpostannounce
        浏览管理日志权限    allowviewlog
        禁止投票权限    allowbanpost
        发贴不受限制    disablepostctrl
        推荐主题权限    supe_allowpushthread
            
后台留言表    cdb_adminnotes    后台留言id    id
        留言人    admin
        阅读权限    access
        管理组id    adminid
        发表时间    dateline
        有效期    expiration
        留言内容    message
            
管理记录    cdb_adminsessions    用户登录id    uid
        管理员id    adminid
        面板    panel
        登录ip    ip
        登录日期    dateline
        密码错误次数    errorcount
        存储    storage

广告缓存    cdb_advcaches    广告id    advid
        类型    type
        投放范围    target
        代码    code

广告资料表    cdb_advertisements    广告id    advid
        是否显示    available
        类型    type
        显示顺序    displayorder
        标题    title
        投放范围    targets
        参数    parameters
        代码    code
        开始时间    starttime
        结束时间    endtime
            
公告表    cdb_announcements    公告ID    id
        发布者用户名    author
        公告标题    subject
        类型    type
        显示顺序    displayorder
        开始时间    starttime
        结束时间    endtime
        公告内容    message
        面向组    groups
            
附件表    cdb_attachments    附件id    aid
        所在主题id    tid
        所在帖子id    pid
        尺寸范围    width
        发布附件时间    dateline
        阅读权限    readperm
        阅读花费金钱    price
        附件的原始文件名    filename
        附件描述    description
        附件类型    filetype
        附件文件的大小    filesize
        上传后的附件的文件名    attachment
        下载/浏览次数    downloads
        附件外观图标    isimage
        用户id    uid
        预览    thumb
        下载地址    remote
            
附件记录表    cdb_attachpaymentlog    记录id    uid
        附件id    aid
        用户id    authorid
        时间    dateline
        大小    amount
        下载次数    netamount
            
附件类型表    cdb_attachtypes    附件类型的ID    id
        类型设置时的扩展名    extension
        控制最大上传大小    maxsize

被禁止的ip列表    cdb_banned    被禁ip列表的id    id
        ip字段1    ip1
        ip字段2    ip2
        ip字段3    ip3
        ip字段4    ip4
        操作者记录    admin
        日期    dateline
        有效期    expiration

自定义Discuz!代码    cdb_bbcodes    数据ID    id
        是否启用    available
        类型    type
        标签    tag
        图标    icon
        替换内容    replacement
        使用举例    example
        代码的解释说明    explanation
        参数个数    params
        参数提示语    prompt
        嵌套次数    nest
        显示次序    displayorder
            
统计页面的缓存    cdb_caches    缓存名称    cachename
        类型    type
        页面缓存的时间    dateline
        到期    expiration
        数据    data

积分交易记录表    cdb_creditslog    用户id    uid
        来自    fromto
        转出积分字段    sendcredits
        接受积分字段    receivecredits
        转出积分    send
        收到积分    receive
        交易时间    dateline
        交易动作    operation

计划任务表    cdb_crons    计划任务id    cronid
        是否可用    available
        类型    type
        名称    name
        任务脚本名称    filename
        上次运行时间    lastrun
        下次运行时间    nextrun
        周    weekday
        天    day
        小时    hour
        分钟    minute

辩论投票    cdb_debateposts    记录id    pid
        支持正、反某方    stand
        辩题id    tid
        用户id    uid
        时间    dateline
        投票数    voters
        投票id    voterids

辩论帖    cdb_debates    帖子id    tid
        作者id    uid
        发起时间    starttime
        结束时间    endtime
        正方辩手    affirmdebaters
        反方辩手    negadebaters
         正方支持数    affirmvotes
        反方支持数    negavotes
        裁判    umpire
        赢者    winner
        最佳辩手    bestdebater
        正方辩题    affirmpoint
        反方辩题    negapoint
        裁判观点    umpirepoint
        正方支持者id    affirmvoterids
        反方支持者id    negavoterids
        正方响应    affirmreplies
        反方响应    negareplies
            
错误登录记录    cdb_failedlogins    非法登入者的IP    ip
        登入的次数    count
        最后更新日期    lastupdate

论坛帮助表    cdb_faqs    id    id
        问题id    fpid
        次序    displayorder
        标识    identifier
        关键字    keyword
        标题    title
        内容    message

个人收藏信息表    cdb_favorites    用户id    uid
        主题id    tid
        收藏id    fid

板块扩展信息数据表    cdb_forumfields    版块id    fid
        版块描述    description
        访问版块所需密码    `password`
        版块图标    icon
        自定义主题积分    postcredits
        自定义回复积分    replycredits
        下载附件管理    getattachcredits
        上传附件管理    postattachcredits
        积分策略    digestcredits
        链接转向地址    redirect
        允许附件类型    attachextensions
        版块权限    formulaperm
        版主    moderators
        版规    rules
        主题分类    threadtypes
        主题整理    threadsorts
        浏览帖子权限    viewperm
        发表主题权限    postperm
        发表回复权限    replyperm
        下载附件权限    getattachperm
        上传附件权限    postattachperm
        关键字    keywords
        推荐设置    supe_pushsetting
        更多建议    modrecommend
        交易类别    tradetypes
        模板    typemodels
            
友情链接数据表    cdb_forumlinks    联盟论坛id    id
        显示顺序    displayorder
        联盟论坛名称    name
        联盟论坛地址    url
        联盟论坛说明    description
        logo地址    logo

版块建议    cdb_forumrecommend    版块id    fid
        主题id    tid
        显示次序    displayorder
        内容    subject
        作者    author
        作者id    authorid
        版主id    moderatorid
        期限    expiration

版块资料表    cdb_forums    论坛版块id    fid
        上级版块id    fup
        版块类型    type
        版块名称    name
        是否显示    status
        显示顺序    displayorder
        默认风格    styleid
        主题信息统计    threads
        帖子信息统计    posts
        今日帖子统计    todayposts
        最新帖子    lastpost
        是否允许表情    allowsmilies
        是否允许html    allowhtml
        是否允许自定义ubb    allowbbcode
        是否允许[img]代码    allowimgcode
        是否允许[media]代码    allowmediacode
        是否允许匿名发贴    allowanonymous
        是否共享    allowshare
        允许发布哪些其他特殊主题    allowpostspecial
        是否只允许发布特殊类型主题    allowspecialonly
        是否允许版主编辑规则    alloweditrules
        允许回复    allowfeed
        是否开启回收站    recyclebin
        是否开启审核新帖    modnewposts
        是否启用干扰码    jammer
        是否禁止使用水印    disablewatermark
        本论坛或分类版主的权力继承到下级论坛    inheritedmod
        自动关闭主题    autoclose
        增加论坛水平横排设置    forumcolumns
        主题缓存    threadcaches
        允许编辑帖子    alloweditpost
        风格    simple
        分区显示    modworks
        是否允许标签    allowtag
        是否显示全局置顶    allowglobalstick
            
图片属性    cdb_imagetypes    属性id    typeid
        是否启用    available
        属性名    name
        属性类别    type
        显示顺序    displayorder
        目录    directory

邀请表    cdb_invites    用户id    uid
        访问时间    dateline
        离开时间    expiration
        邀请ip    inviteip
        邀请码    invitecode
        注册id    reguid
        注册时间    regdateline
        状态    status

    cdb_itempool    id    id
        类别    type
        问题    question
        回答    answer

道具记录    cdb_magiclog    用户id    uid
        道具id    magicid
        动作    action
        时间    dateline
        数目    amount
        价格    price
        使用主题id    targettid
        使用商品id    targetpid
        使用对象id    targetuid
            
道具商店    cdb_magicmarket    市场id    mid
        道具id    magicid
        用户id    uid
        用户名    username
        价格    price
        数目    num
            
道具    cdb_magics    道具id    magicid
        启用    available
        类型    type
        名    name
        标识    identifier
        描述    description
        次序    displayorder
        价格    price
        数目    num
        保存容量    salevolume
        提供对象类型    supplytype
        提供数目    supplynum
        负重    weight
        文件    filename
        道具权限    magicperm
            
勋章记录    cdb_medallog    记录id    id
        用户id    uid
        勋章id    medalid
        类型    type
        时间    dateline
        到期    expiration
        状态    status
            
勋章资料表    cdb_medals    勋章id    medalid
        勋章名称    name
        是否可用    available
        勋章图片    image
        类型    type
        显示次序    displayorder
        描述    description
        期限    expiration
        勋章领取权限    permission
            
用户扩展资料表    cdb_memberfields    用户uid    uid
        用户昵称    nickname
        用户主页    site
        支付宝号码    alipay
        icq号码    icq
        qq号码    qq
        yahoo通号码    yahoo
        msn号码    msn
        淘宝帐号    taobao
        来自    location
        自定义头衔    customstatus
        勋章信息    medals
        头像信息    avatar
        头像宽度    avatarwidth
        头像高度    avatarheight
        自我介绍    bio
        解析后的签名    sightml
        忽略短消息列表    ignorepm
        公众用户组信息    groupterms
        待审核用户    authstr
        空间名    spacename
        买家信誉    buyercredit
        卖家信誉    sellercredit

成员道具    cdb_membermagics    用户id    uid
        道具id    magicid
        数目    num
posted @ 2009-05-24 14:13 awp110 阅读(1038) 评论(0) 编辑
一个人自娱自乐的写个小程序,跟一帮人一起写个大程序。真的是不一样。

自己一个人,根本就不存在交流,相互理解的问题。人越多,理解他人意图,向他人解释意图就越来越花时间。只要是需要交流的任务,并非是人越多越好。有人加入,为了使加入的人有事做,原来的事就要重新划分,而分开之后要配合,又要花时间交流。发觉很多重要的软件开始都是几个人做出来的。而漫画中,进行任务也采用小组模式,好像<幽游>, <猎人>都是四人小组。

这里,最基本的问题就是任务的划分,最理想的划分是相互独立。而要做到这种独立,正交的划分,是很困难的,更困难的是你会发现那最初的任务会随着时间变动。传统的软件工程会说,首先是定义需求,跟着大体设计,详细设计,编码,单元测试,整体测试等等。但真正实施起来,发觉没有那样理想,很多项目都不是重新编写,而是在原有的代码上加强,很可能原来的根本就是沙地,很是流沙,而却要在上面起高楼。假如一个项目规定是半年完成,花上一个月去定义需求和设计,跟着去编码了,就会发现很多事情是想不到的,有些看来很简单的事一卡就卡上一个月,毫无进展。发觉这本来是很简单的问题牵涉到项目的结构,而之前结构很难修改,又或者不舍得去修改,为解决这问题,就使出一些歪招,看起来好像很巧妙,却打乱了原来的结构,跟着这些古古怪怪,想不到的问题一个个冒出,原来的设计渐渐偏离,又没有去修改文档。时间越来越紧,项目拖后,公司上层发觉不对路了,就加人,新人来,拿起最初的设计文档看,发觉根本对不上。旧人就又花时间会帮他理解项目。到原定的发布限期,程序却一运行就死机,最终结果迟上两三个月发布,发布之后很多bug, 再花两三个月改错,发个补丁包。一年就此过去。

软件中常说的任务划分,其实就是要确立边界条件。比如划分出组件,组件中划分出类,组件与组件,类和类交互都要通过一些接口。边界条件最容易出问题。本来我这个类好好的,一和另一个类交互,就出问题了,又比如这个函数好好的,一到线程切换那一瞬间就出问题。接口的定义很重要。软件还没有完全做到硬件那样即插即用。先确立接口,跟着找不同的人做实现,最后嵌起来就可以用,这也是很理想的一种情况。很可能最初那样划分接口就错了,另一种可能是实现者理解错了接口的含义。很多事,做完了才知道是做错了。比如考试,通常考完出来就知道答案,想着下次好好准备,考好点,却发觉下次还是有题目是不会做。

我现在自己的意见(以后可能也会变), 项目初期是无论如何都想不出具体的细节的,所以只要有个大方向就可以了, 要尽快动手做。既然之前没有想出所有细节,就强调要可以很容易的调整代码的结构,添加更多的细节,也就是重构。注意,重构并非是添加新功能,而是在不改变程序表现的情况下整理代码,使原来的代码更合理,之后再添新功能就容易了。而所谓的添个if来判断空指针,再对话框上面加个按钮等等,就不算是重构了。

为修改代码更容易,应该注意某些小细节。特别是工程比较大的时候。有些习惯要一开始就养成,不要想着只是做些小玩意玩玩,没有关系啦。一开始就应向着这行业最top的那批人看齐,这样才有可能做到专业。


1. 减少编译连接时间,特别尽量不要在头文件上加头文件。

   以前也很随意的乱加头文件,反正小工程,一下就编译完了。现在发觉只要我改某个头文件,等它编译完够看一章书了,经过编译折磨,才发觉这很重要。因为头文件一修改,包含或者间接包含的cpp文件就要被编译。乱包含,会发现底层的文件一改,几乎整个工程都编译,是很费时间的。另外就不要将所有类定义都写在一个地方,这样包含依赖会减少一些。
   如果编译时间很长,明明知道有些地方不妥,也不会去修改的。好像写程序的都很怕麻烦。
   
   
2. 变量用到才定义,不要一开始就定义。

   很多人还保留C的习惯,将所有用到的变量都定义在函数开头。这习惯其实很不好,一方面没必要的构造析构会被调用。更重要的是,你会发觉以后想将原来的函数分解成一些小函数时候,会很麻烦,因为定义在开头,作用域是整个函数的,你想提出一段代码,很难确定那些变量要用到,那些不用。另外变量定义一定要附上初始值,这个错误看起来很弱智,但很多人会犯,特别是喜欢将所有变量就放在开头的那种C风格的人。
   
   
3. 用类管理资源,获取资源跟释放资源尽量在同一个地方,不要分开在两处。特别是不要在同一个函数中不要new, delete同一对象或者数组。

    资源是很广义的,比如取gdi对象和释放,常说的是内存。要复制一个字串,或要暂时读一内存,开始又不知道长度,很多人会new 一个char数组,跟着函数末尾在释放。这样就有问题,比如中间有一个return, 跳过了释放的语句,就有资源泄露。对此很多人坚持一个函数一个出口,但是这样往往有一些变量标记性着是否结束循环等等,远不如一个return直接。另外换另一个人来修改代码,他很可能不信奉一函数一出口。随着函数修改变长,对应的获取释放相隔越来越远。怕麻烦,为了不在每个return之前添上释放代码,有人就用goto out: 替代return, out:之后做释放。
    只要出现goto, 资源跟释放隔太远,以后想将一些代码提出来,做成另一个函数,就很麻烦。
    所以C++有个惯用法RAII, 简单理念是用类来管理资源,在构造函数中获取,在析构释放。因为标准保证每个出口,已生成的对象其析构会被调用,包括发生异常。如果要分配char数组,可以用std::vector<char> mem; mem.resize(memSize)来替代, new char[memSize];, 之后的指针可以写成&mem[0]。 有人可能会说,如果对象太大,可能直接定义会引起栈溢出,所以要new. 如果真的是这样,很可能是那个对象的设计本身就有问题。要是老是写这样一些释放的辅助类很烦人,看看Loki::ScopeGuaid.
    
    
4. 风格保持一致
    风格看起来是很个人,很细微的事情,但对于一帮人保持协调也是很重要,最忌的是团队每个人,或者个人在不同时候的风格都不一样。因为风格不同,在从一种风格逃到另一种风格时,思维上会卡一卡。另外接口命名的风格不一样,就很容易的将接口用错。
    比如,有个迭代器类,要判断前进是否合理,有千奇百怪的名字,hasMove, hasMoveElements, isCurValie, isValie, isOk isLegal。又或者判断有几个元素,有名字getLength, length, size, numElemnts, totalElements。你用那些类,大概会骂最初写代码的那批人太白痴。但想想,有几个人是会将风格保持一致的。
    其实风格本身没有好坏,最怕的是不统一,选择一种,跟着用就是了。但现实种往往是一批人同做一项目,各人都有自己写法,还鄙视他人的写法。假如A是取名成stl那风格,小写加下划线,B取命成MFC那种,C取名成java那种,看起来会很累。这个问题是很普遍的,写代码的很多人都很聪明,也很自傲,往往觉得自己做的才是最好的。
    另一点是,相同功能类的那些函数接口,如果有同样的函数,应该将名字取成一致,不要搞得很乱。
    一帮人一起会做一件事,会确立规矩,比如一起会玩游戏啊,出去玩啊,会商议定个时间。有类人当别人商量规矩时候,他不出声,或者是做别的事,比如玩手机发短信之类。规矩定好了,自己不清楚,就老是问,或者犯规了就怪规矩定得不合理。这类人是很影响士气的,观察一下,你身边应该会有类似的人。
    
    

5. 最后一条,老原则,Keep it simple and stupid.

    程序首先是给人看的,之后才是被计算机看的。一定要简单。比如接口设计开始要最简化,不要想着这接口以后会用到就加上,要想着以后可能没有用就去掉。如果你自我陶醉,觉得自己很聪明,这样巧妙的代码也可以写得出,将来还有什么软件写不出来,注意,这样想会有问题。因为越是巧妙的代码,以后修改的人会越难理解,越容易出错。其实简单的代码才难写。最好的设计应是理所当然,顺理成章的,感觉不到有多巧妙。<孙子>中有句话,善战者,无功名,无勇功。因为他们去打仗,打之前就赢定了,根本就不需要很勇敢,很激烈才能打赢,一切顺理成章,好像没有什么难度,自然不会被人去歌颂。同样,需要很巧妙的方法才能解决某问题,本身就落下乘。
posted @ 2009-05-24 08:57 awp110 阅读(14) 评论(0) 编辑