一直覺得,簡單也是一種美,架構如此,做人亦如此;重劍無鋒,真水無香
為了便於大家理解,在此放出源代碼:點擊此處下載
強烈建議配合代碼閱讀本文,畢竟代碼才是程序員最好的交流方式
之前的文章分析了系統,並畫出了架構草圖,詳情請見《一步一步搭架子(分析篇)》
關於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:變天了,各位園友記得防寒保暖 :)