一步一步搭架子(Model继承与Factory层)

一直觉得,简单也是一种美,架构如此,做人亦如此;重剑无锋,真水无香

为了便于大家理解,在此放出源代码:点击此处下载

强烈建议配合代码阅读本文,毕竟代码才是程序员最好的交流方式

 

之前的文章分析了系统,并画出了架构草图,详情请见《一步一步搭架子(分析篇)

关于ModelBase层与Model层的实现,因为很简单,就不再赘述了,直接上代码即可。关于Model继承的思路,请见:《我们该如何设计数据库(三)(续)

ModelBase代码:

namespace ModelBase
{
    public class Identifier
    {
        [Key]
        public Guid ID { get; set; }
    }

    public class TeacherBase : Identifier
    {
        [StringLength(50)]
        public string UserName { get; set; }

        [StringLength(50)]
        public string Pwd { get; set; }
    }

    public class ContactBase : Identifier
    {
        [Required]
        public Guid TeacherID { get; set; }

        [StringLength(50)]
        public string Phone { get; set; }

        [StringLength(50)]
        public string Email { get; set; }
    }
}

可以看到,数据在这一层是还没有组合在一起的;然后是Model代码(假设现在是提供给A学校的):

namespace Model.A
{
    public class Teacher : TeacherBase
    {
        [StringLength(50)]
        public string FirstName { get; set; }

        [StringLength(50)]
        public string LastName { get; set; }

        public Contact Contact { get; set; }
    }

    public class Contact : ContactBase
    {
        public DateTime CreateTime { get; set; }
    }
}

可以看到,Teacher中包含了Contact。我习惯称这种为“数据耦合在一起”,虽然我不知道这种叫法对不对。欢迎留言指正这种说法

请注意,这里用Model.A的命名空间来区分了Model。如果是B学校的Model,要这样写:

namespace Model.B
{
    public class Teacher : TeacherBase
    {
        [StringLength(50)]
        public string Number { get; set; }
    }

    public class Contact : ContactBase
    {
    }
}

可以看到,A学校和B学校Model的命名都是Teacher 和Contact ,用不同的命名空间来加以区分

 

再然后是DBcontext的实现:

using System.Data.Entity;
using Model.A;

namespace DBaccess.A
{
    public class Context : DbContext
    {
        public Context()
        {
            //this.Configuration.AutoDetectChangesEnabled = false;
            //this.Configuration.LazyLoadingEnabled = true;
            //this.Configuration.ProxyCreationEnabled = false;
            //this.Configuration.ValidateOnSaveEnabled = false;
        }

        public DbSet<Teacher> Teacher { get; set; }
        public DbSet<Contact> Contact { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Teacher>()
                .Ignore(o => o.Contact);          //Teacher中的Contact不映射到数据库中
        }     
    }
}

 

然后就是系统中的难点:Factory的设计

一开始,我觉得这个就是抽象工厂模式所描述的应用场景:同类产品不同产品族的开发

但是在实际开发过程中,却发现抽象工厂无法满足需要。抽象工厂要求子类从基类派生,这点我们的Model是由ModelBase派生的,满足条件;但是我们不同的Model还有自己独有的get/set方法,而这些独有的方法是无法通过抽象工厂完成的

简单的反射也无法满足要求。反射出来的是一个Object类型,要通过as关键字转换之后才能使用,如:

            Object obj = Assembly.Load("").CreateInstance("");   //假设这里反射出一个Teacher
            Teacher teacher = obj as Teacher;                    //还要as之后才能使用

 

我在这个问题上耗费了一个星期多的时间,直到有一天,灵感突现:可以使用预编译指令来实现NameSpace的切换

#define A
#if B
using Model.B;
using DBaccess.B;
#endif
#if A
using Model.A;
using DBaccess.A;
#endif

这样的话,我们切换Model,只需将#define A改为#define B

Factory的具体实现如下:

#region NameSpace
#define A
#if B
using Model.B;
using DBaccess.B;
#endif
#if A
using Model.A;
using DBaccess.A;
#endif
#endregion
using System.Collections.Generic;

namespace Factory
{
    public class ModelFactory
    {
        public static Teacher GetTeacher()
        {
            return new Teacher();
        }       

        public static Contact GetContact()
        {
            return new Contact();
        }   
    }

    public class ModelListFactory
    {
        public static IList<Teacher> GetTeacherList()
        {
            return new List<Teacher>();
        }

        public static IList<Contact> GetContactList()
        {
            return new List<Contact>();
        }
    }

    public class ContextFactory
    {
        public static Context GetContext()
        {
            return new Context();
        }
    }
}

这样弄出来的Factory,如其名字一样,用了最简单的工厂模式来实现

 

就此搁笔

 

PS:变天了,各位园友记得防寒保暖  :)

posted @ 2012-10-23 10:26  CrazyJinn  阅读(2857)  评论(13编辑  收藏  举报