一直觉得,简单也是一种美,架构如此,做人亦如此;重剑无锋,真水无香
为了便于大家理解,在此放出源代码:点击此处下载
强烈建议配合代码阅读本文,毕竟代码才是程序员最好的交流方式
之前的文章分析了系统,并画出了架构草图,详情请见《一步一步搭架子(分析篇)》
关于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:变天了,各位园友记得防寒保暖 :)