求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
  
 
 
 
   
分享到
代码设计简单规范
 

作者:jackey zhang ,发布于2012-10-18,来源:博客园

 

下面这个规范是我为朋友写的几点建议,写的很范,作为BLOG,愿与大家一起分享。

下面只给出部分设计规范样例,关于.NET编程的详细规范、设计请参考相关书籍。

1、命名规范

1.1 命名空间命名,一般命名为”公司简称+产品名称+程序包”的形式,如ARSC.EngineMap.Geometry、SharpMap.Framework、SharpMap.Controls、GoogleMap.Downloader、GoogleMap.App等,其长度一般要求不能过于太长。程序集的名称可以和命名空间保持一直。注意可以在不同的.DLL里面定义相同的命名空间。

1.2 变量命名,如果是局部变量、函数接口变量,主要以易于表达概念的英语进行命名。单词第一个字符必须小写,如果是组合单词,第二个单词应该大写,如firstName、computerName。

Public void ConcactName (string firstName,string lastName);

对于成员变量需要定义以”_”开头,如:

Public class Person
{
   Private string _firstName;
   Private string _lastName;
   Private int   _age;
}

1.3 类命名,类主要由名词性短语命名,类的第一个单词都是大写,做到见名知意,如Person、Computer、ExtensionManager、PrintManager、FormatTransform、HttpDownloader、TcpDownloader、CommandPool、XmlHelper、XmlUtility、ProductFinder、ProductRepository、CourseCatalog等。注意的是类命名不能加复数形式如Persons表示人的集合,正确命名应该为PersonCollection。

1.4 接口命名,接口命名可以参考类命名规则,但是其需要在命名前加”I”。如ICommandPool、IDownloader、IPrintManager、IProductFinder等。

1.5 方法命名,主要以动名词短语构成,函数主要表达一种计算功能或者任务,因此给函数取一个合适的名字非常重要,如CaculateArea、QueryProduct、CreateBar、ExportView、CanSeek、HasValue、HasChildern等。长名称函数一般用于私有函数中,如CopyProductsToRepositoryFromCache这个函数要比注释好的多。

1.6 代理命名,如提供回调的代理需要加上CallBack后缀:

Public delegate void ProgressNotificationCallBack(int curPos,int totalSize);提供事件原型的代理需要加上EventHandler后缀,如:

Public delegate void CurrentToolChangedEventHandler(object sender,MapToolEventArgs e);

1.7 事件命名,主要是要能够见名知意,如

Public event CurrentToolChangedEventHandler CurrentToolChanged;

Public event EventHandler CurrentLayerChanged;

1.8 属性命名,提供私有成员的访问控制如

Public string Name
{
     Get{return _name;}
     Set 
       {
          If(value==null)
          Throw new ArgumentNullException(“Name can’t be set null.”);
          _name=value;
       }
}

2、成员访问控制

成员访问控制主要由internal(在该DLL内可以访问)、protected(子类可以访问)、private(私有访问)、public(访问不受控制)和Protected internal(在其子类或者该DLL内部可以访问),我们将所有成员变量都设计成私有,如果需要公开该数据,需要提供属性。如:

Public class Person
{
    Private string _name;
    Public string Name
    {
        Get{return _name;}
        Set {_name=value;}
    }
}

3、XML代码注释

对于公开函数接口必须提供代码XML注释,便于形成开发文档。私有函数可适当加以注释。详细请参考MSDN。

    /// <summary>
    /// 命令池对象,主要用于命令按钮的注册和反注册。
    /// </summary>
    ///<remarks>
    ///每一个命令池都和一个<seealso cref="ICommandBars"/>绑定在一起,
    ///如果想将按钮添加到<seealso cref="ICommandBars"/>上,首先必须在命令池中注册该按钮项目。
    ///</remarks>
    public interface ICommandPool
    {
        /// <summary>
        /// 获取命令池中工具条项目。
        /// </summary>
        /// <param name="uid">命令按钮全局唯一标识符。</param>
        /// <returns>返回工具条项目。</returns>
        ICommandItem GetCommandItem(GuidClass uid);
        /// <summary>
        /// 获取和设置应用程序钩子其为<seealso cref="Jackey.Framework.IApplication"/>。
        /// </summary>
        object Hook { get; set; }
        /// <summary>
        /// 获取和设置COM对象钩子。该钩子只需要在COM应用程序中进行设置。
        /// </summary>
        object COMHookObject { get;set;}
        /// <summary>
        /// 获取和设置命令按钮单击回调函数。
        /// </summary>
        ButtonClickCallBack ButtonClick { get;set;}
        /// <summary>
        /// 利用指定全局唯一标识符注册命令按钮。
        /// </summary>
        /// <param name="cmd">命令对象。</param>
        /// <param name="guid">命令按钮全局唯一标识符。</param>
        /// <returns>返回工具条项目。</returns>
        ICommandItem RegisterCommandItem(ICommandObject cmd, GuidClass guid);
		
        /// <summary>
        /// 利用指定全局唯一标识符注册命令按钮。
        /// </summary>
        /// <param name="cmd">命令对象。</param>
        /// <param name="cmdType">工具条项目类型</param>
        /// <param name="guid">命令按钮全局唯一标识符。</param>
        /// <returns>返回工具条项目。</returns>
        ICommandItem RegisterCommandItem(ICommandObject cmd, CommandTypeEnum cmdType, GuidClass guid);
 
        /// <summary>
        /// 从配置文件中注册所有已配置的命令按钮项目。
        /// </summary>
        /// <param name="exeConfigPath">配置文件路径</param>
        void RegisterCommandItemFromConfiguration(string exeConfigPath);
 
        /// <summary>
        /// 注销所有命令按钮。
        /// </summary>
        void UnRegisterAll();
 
        /// <summary>
        /// 注销指定全局唯一标识符的命令项目。
        /// </summary>
        /// <param name="cmdID">命令按钮全局唯一标识符。</param>
        void UnRegisterCommandItem(GuidClass cmdID);
 
     }

 再如:

    /// <summary>
    ///从XML文件中提取工具条和按钮,动态生成系统菜单,菜单生成算法存储于菜单生成指导者类.
    /// </summary>
    public class XmlCommandBuilder:ICommandBuilder
    {
        #region private and protected members
 
        private ICommandBars iCmdBars;
        private List<ICommandBar> _cmdBarList;
 
        /// <summary>
        /// xml document.
        /// </summary>
        protected XmlDocument _document;
 
        /// <summary>
        /// tool bar item command id.
        /// </summary>
        protected readonly static string COMMAND_ITEM_GUID = "commandid";
 
        #endregion
 
        /// <summary>
        /// 构造函数。
        /// </summary>
        /// <param name="xmlConfigPath">工具条配置文件路径。</param>
        /// <param name="cmdBars">工具条管理器接口。</param>
        /// <exception cref="System.ArgumentNullException">当xmlConfigPath为空抛出该异常。</exception>
        /// <exception cref="System.ArgumentNullException">当cmdBars为空抛出该异常。</exception>
        public XmlCommandBuilder(string xmlConfigPath,ICommandBars cmdBars)
        {
            if (String.IsNullOrEmpty(xmlConfigPath))
                throw new ArgumentNullException("xmlConfigPath can't be null or empty.");
            if (cmdBars == null)
                throw new ArgumentNullException("cmdBars can't be null.");
            this.iCmdBars = cmdBars;
            _document = new XmlDocument();
            _document.Load(xmlConfigPath);
        }
    } 

4、标准模式设计

4.1标准IDispoable模式设计

对于具有非托管资源,如文件指针、数据库连接、套接字等必须实现标准IDisposable模式。对于组合实现IDisposable的类也应该实现IDisposable模式。

下面是一个标准实现IDisposable的类。

    public class BaseClass:IDisposable
    {
        private FileStream _readStream;
        private FileStream _writeStream;
        protected bool _disposed;
 
        //如果该类没有非托管资源则注释该终结器函数,该函数的添加会从一定
        //程度上损伤程序性能。
        ~BaseClass()
        {
            this.Dispose(false);
        }
        //允许子类重写该函数。
        protected virtual void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                if (disposing)
                {
                    //这里释放托管资源
                    if (_readStream != null)
                        _readStream.Dispose();
                    if (_writeStream != null)
                        _writeStream.Dispose();
                }
                //这里释放非托管资源
                //do something release unmanaged resources.
                _disposed = true;
            }
        }
        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }
}
public class DerivedClass:BaseClass
    {
        private FileStream _myStream;
        //如果该类没有非托管资源则注释该终结器函数,该函数的添加会从一定
        //程度上损伤程序性能。
        ~DerivedClass()
        {
            this.Dispose(false);
        }
        public void ReadNextChunk()
        {
            if (_disposed)
                throw new ObjectDisposedException("object has been disposed.");
            //do the real thing.
        }
        protected override void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                try
                {
                    if (disposing)
                    {
                        //这里释放托管资源
                        if (_myStream != null)
                            _myStream.Close();
                    }
                    //这里释放非托管资源
                }
                finally
                {
                    base.Dispose(disposing);
                }
                //这句可以不加。
                _disposed = true;
            }
        }
    } 

5、.Net开发几点性能和设计问题的建议:

5.1 避免在一个大的循环里面执行装箱和拆箱操作。解决办法是利用泛型如List<T>取代ArrayList。

   ArrayList list = new ArrayList();
   for (int i = 0; i < 10000;i++ )
   {
                //装箱
                list.Add(i);
                //拆箱
                Debug.WriteLine(list[i].ToString());
   }

5.2 对于复杂的事件交互的系统,在每个类被终结前确保其已经注销所有事件。否则及易发生内存泄露。这种情况在.Net和COM互操作中经常出现,如ArcObject的各种事件。

5.3 对于工具类如WorkspaceHelper(封装AO的工作空间操作的类)应该做到简单和易于理解,不要把Helper和Utility类当作大杂烩,什么方法都往里面放,这将导致代码非常难以修改。工具类的方法大都为静态方法,该类也为静态类。尽量不要把类设计为静态类,一旦设计成静态类,将无法利用多态的优势。

相关文章

深度解析:清理烂代码
如何编写出拥抱变化的代码
重构-使代码更简洁优美
团队项目开发"编码规范"系列文章
相关文档

重构-改善既有代码的设计
软件重构v2
代码整洁之道
高质量编程规范
相关课程

基于HTML5客户端、Web端的应用开发
HTML 5+CSS 开发
嵌入式C高质量编程
C++高级编程


WEB应用程序UI模版代码编写
C# 编码规范和编程好习惯
什么是防御性编程
善于防守-健壮代码的防御性
Visual C++编程命名规则
JavaScript程序编码规范
更多...   


设计模式原理与应用
从需求过渡到设计
软件设计原理与实践
如何编写高质量代码
单元测试、重构及持续集成
软件开发过程指南


某全球知名通信公司 代码整洁
横河电机 如何编写高质量代码
某知名金融软件服务商 代码评审
东软集团 代码重构
某金融软件服务商 技术文档
中达电通 设计模式原理与实践
法国电信 技术文档编写与管理
更多...