Asp.Net大型项目实践(3)-业务领域对象建模

你是不是已经厌倦了和数据库表一一对应的Model或Entity? 
Ok~我们现在尝试真正的用面向对象的思想去设计我们的业务实体类吧....
 
注:这里我并不是说和数据库表一一对应的Model这种做法有多么不好,因为毕竟表驱动设计模式经过这么多年的实践,到现在也具有很强的生命力 。并且我也用这样的设计做项目多年,可是一直存在一个疑惑,为啥在处理业务的时候大牛们所鼓吹的面向对象编程思想几乎一点都没用到呢?所以这里我们做一下新的尝试,也许由于各种具体实现技术的限制和我水平有限这种尝试可能并不彻底...

  1. 按照国际惯例,我们新建一个抽象类,作为我们系统中所有业务对象的基类,将来可以用来识别哪些类是我们自己的业务对象类
     
    namespace Demo.HIS.FrameWork.DomainBase
    {
    /// <summary>
    /// 系统所有业务类都要继承的基类
    /// </summary>
    [Serializable]
    public abstract class BaseObject
    {
    }
    }

     

  2. 一般在信息管理系统中,大多数的业务对象都需要持久到数据库,所以我们再新建一个抽象类作为所有可以被持久化的业务对象都要继承的基类
     
    代码
    namespace Demo.HIS.FrameWork.DomainBase
    {
    /// <summary>
    /// 可以持久到数据库的业务类都要继承的基类
    /// </summary>
    public abstract class Entity : BaseObject
    {
    public Entity()
    {
    Id
    = Guid.NewGuid().ToString();
    CreateTime
    = DateTime.Now;
    IsDelete
    = false;
    }
    public virtual string Id { get; protected set; }
    public virtual DateTime CreateTime { get; protected set; }
    public virtual bool IsDelete { get; set; }
    public virtual Int32 Version { get; protected set; }
    }
    }

    a.Entity继承了BaseObject。因为Entiy也是业务对象,只不过它是可以持久化的业务对象。 
    b.为啥所有属性都要用virtual? 因为我们需要用NHibernate来做持久化,它要求属性必须是virtual,如果你还要问为啥NHibernate需要用virtual,据我所知NHibernate移植自Java的Hibernate,在Java里virtual是常态,为了移植方便 所以沿用...其实就算NHibernate不需要virtual,我也会写成virtual....这样子类可以重写,是不是很罗嗦....?

    c.所有可以持久到数据库中对象都有Id属性,别告诉你数据库里的表没有Id字段做为主键(特殊情况可能没有...比如多对多关联表)。为啥我的Id数据类型是string? 项目很大,生命周期也长,指不定啥时候因为某种原因需要改变Id的数据类型(我就遇到过...)所以我们不把Id的数据类型定死为int或guid,而且把Id的生成方式放在这个基类的构造函数里,注意Id = Guid.NewGuid().ToString();这里我们的Id生成方式采用GUID。

    d.为了防止误删除,以及一些表间关联情况下删除而导致程序出错,我们系统中默认的删除一般都是逻辑删除,所以用IsDelete字段进行标识(这样可能产生不少垃圾数据,以后我们可以进行过期删除处理或转移之类的功能来避免)。
    e.Version字段是 提供给NHibernate处理并发用的。
    f.CreateTime有啥用?我也不知道....

  3. 应用场景举例之InputItem
    在我们的项目中经常需要用到各种下拉选择项,而且客户要求很BT,供选择的项可能从几个到上万个不等,而且为了快速录入需要模糊输入汉字,编码,拼音,五笔都可以检索到想要选择的项,如下图(这是B/S的用EXT实现):

    于是我们想到为系统中所有需要这样录入的对象建立一个基类:

    代码
    namespace Demo.HIS.FrameWork.DomainBase
    {
    /// <summary>
    /// 下拉输入项实体
    /// </summary>
    public abstract class InputItem : Entity
    {
    private string name;
    private string code;
    /// <summary>
    /// 文本值
    /// </summary>
    public virtual string Name
    {
    get
    {
    return this.name;
    }
    set
    {
    if (String.IsNullOrEmpty(value))
    throw new NotNullException();
    this.name = value;
    }
    }
    /// <summary>
    /// 编码
    /// </summary>
    public virtual string Code
    {
    get
    {
    return this.code;
    }
    set
    {
    if (String.IsNullOrEmpty(value))
    throw new NotNullException();
    this.code = value;
    }
    }
    /// <summary>
    /// 助记码
    /// </summary>
    public virtual string InputCode1 { get; set; }
    /// <summary>
    /// 助记码2
    /// </summary>
    public virtual string InputCode2 { get; set; }
    /// <summary>
    /// 助记码3
    /// </summary>
    public virtual string InputCode3 { get; set; }
    }
    }
    NotNullException是我定义的异常类 ,这里可以暂时不用管它
    有了这个类,如上图的那个“服务项目类”我们可以这样写:
    代码
    namespace Demo.HIS.Infrastructure.Core
    {
    /// <summary>
    /// 服务项目
    /// </summary>
    public class ServiceItem : InputItem
    {
    //ServiceItem属性1
    //ServiceItem属性2
    }
    }

     

  4. 应用场景举例之User
    比如在我们的项目中可能登录我们系统的用户角色可能有 医生,护士,患者,医院行政人员,这几个对象的都应该属于系统用户对象
    所以我们可以建立一个User抽象类,包含基本的用户名,密码等属性,且包含一些系统用户的方法比如登录,注销,修改密码等等....
    然后针对 医生,护士,患者,医院行政人员这几个对象分别建类继承User抽象类,各自的对象中包含各自的属性和方法
    具体的代码我就不贴了,反正这个系列以后会讲到...

以后我们的业务对象都按照这样的思路去设计,和以前我们单调的和数据库表一一对应的实体类比较起来,这样写是不是比较OO且比较有趣一些呢?

大套的理论到处都有这里就不吹了,至少我个人觉得这样写感觉上比较有设计感一些,而且对于应对需求变更的应付能力也强了很多

posted on 2009-12-24 19:33  传说中的弦哥  阅读(18056)  评论(19编辑  收藏  举报

导航