[Architecture] : Entity Profile
動機 :
前一篇 [Architecture] : Entity Expansion模式,介紹了一種擴展物件屬性資料的模式。本文延續上一篇的動機,介紹一個Entity Profile模式。
Entity Profile模式主要是定義一組,資料物件(Entity)以及邊界物件(Repository)的生成、結構、行為模式,用來擴展物件的屬性資料。實作這個模式,可以為系統加入增加式程式碼累積的能力。
基礎平台 :
結構
參與者
Page Shell
-頁面的殼層,可以透過設定資料,動態掛載系統頁面的系統。
範例程式
Page Shell依照開發平台的不同,會有不同的選擇。 例如以ASP.NET的平台來說,可以直接套用ASP.NET的頁面機制,然後再另外建立一個索引頁面,用修改索引頁面的方式來達成動態掛載系統頁面的需求。
基礎專案 :
結構
參與者
UserManagePage
-User管理頁面,提供新增、修改、刪除、查詢 User的功能。
-使用例如 Spring.Net、Provider Pattern來反射生成 IUserProfileRepository。
-使用生成的 IUserProfileRepository生成 UserRepository。
-使用 UserRepository新增、修改、刪除、查詢 User。
UserProfile
-進出系統邊界的資料物件。
IUserProfileRepository
-資料物件 UserProfile進出系統邊界的介面。
-提供新增、修改、刪除、查詢等功能。
User
-系統運作使用的資料物件。
-屬性資料存放於 UserProfile。
UserRepository
-資料物件 User進出系統邊界的介面。
-使用 IUserProfileRepository,處理自資料物件 User取得的 UserProfile。
-提供新增、修改、刪除、查詢等功能。
範例程式
namespace CLK.EntityProfile
{
public class UserManagePage
{
public void ShowUser()
{
// GetData
IUserProfileRepository userProfileRepository = null; // 使用例如Spring.Net、Provider Pattern來反射生成。(Base專案生成、Ex專案生成,均生成同一個 IUserProfileRepository)
UserRepository userRepository = new UserRepository(userProfileRepository);
IEnumerable<User> userCollection = userRepository.GetAll();
// Show
this.ShowUser(userCollection);
}
private void ShowUser(IEnumerable<User> userCollection)
{
//.....
}
}
public class UserProfile : Dictionary<string, string>
{
public Guid UserID { get; set; }
}
public interface IUserProfileRepository
{
// Methods
void Add(UserProfile item);
void Modify(UserProfile item);
void Remove(Guid id);
UserProfile GetByID(Guid id);
IEnumerable<UserProfile> GetAll();
}
public class User
{
// Properties
protected internal UserProfile Profile { get; private set; }
public Guid UserID
{
get
{
return this.Profile.UserID;
}
set
{
this.Profile.UserID = value;
}
}
public string Name
{
get
{
return Convert.ToString(this.Profile["Name"]);
}
set
{
this.Profile["Name"] = value;
}
}
public string Description
{
get
{
return Convert.ToString(this.Profile["Description"]);
}
set
{
this.Profile["Description"] = value;
}
}
// Constructor
public User()
{
this.Profile = new UserProfile();
this.UserID = Guid.Empty;
this.Name = string.Empty;
this.Description = string.Empty;
}
}
public class UserRepository
{
// Properties
private readonly IUserProfileRepository _userProfileRepository = null;
// Constructor
public UserRepository(IUserProfileRepository userProfileRepository)
{
#region Require
if (userProfileRepository == null) throw new ArgumentNullException();
#endregion
_userProfileRepository = userProfileRepository;
}
// Methods
private User CreateUser(UserProfile userProfile)
{
#region Require
if (userProfile == null) throw new ArgumentNullException();
#endregion
User user = new User();
user.UserID = userProfile.UserID;
foreach (string key in userProfile.Keys)
{
user.Profile.Add(key, userProfile[key]);
}
return user;
}
private UserProfile CreateUserProfile(User user)
{
#region Require
if (user == null) throw new ArgumentNullException();
#endregion
return user.Profile;
}
public void Add(User item)
{
#region Require
if (item == null) throw new ArgumentNullException();
#endregion
_userProfileRepository.Add(this.CreateUserProfile(item));
}
public void Modify(User item)
{
#region Require
if (item == null) throw new ArgumentNullException();
#endregion
_userProfileRepository.Modify(this.CreateUserProfile(item));
}
public void Remove(Guid id)
{
#region Require
if (id == Guid.Empty) throw new ArgumentNullException();
#endregion
_userProfileRepository.Remove(id);
}
public User GetByID(Guid id)
{
#region Require
if (id == Guid.Empty) throw new ArgumentNullException();
#endregion
return this.CreateUser(_userProfileRepository.GetByID(id));
}
public IEnumerable<User> GetAll()
{
List<User> itemCollection = new List<User>();
foreach (UserProfile userProfile in _userProfileRepository.GetAll())
{
itemCollection.Add(this.CreateUser(userProfile));
}
return itemCollection;
}
}
}
擴展專案 :
結構
參與者
ExUserManagePage
-ExUser管理頁面,提供新增、修改、刪除、查詢 User的功能。
-使用例如 Spring.Net、Provider Pattern來反射生成 IUserProfileRepository。
-使用生成的 IUserProfileRepository生成 ExUserRepository。
-使用 ExUserRepository新增、修改、刪除、查詢 ExUser。
ExUser
-系統運作使用的資料物件。
-屬性資料存放於 UserProfile。
ExUserRepository
-資料物件 ExUser進出系統邊界的介面。
-使用 IUserProfileRepository,處理自資料物件 ExUser取得的 UserProfile。
-提供新增、修改、刪除、查詢等功能。
範例程式
namespace CLK.EntityProfile.Expanded
{
public class ExUserManagePage
{
public void ShowExUser()
{
// GetData
IUserProfileRepository userProfileRepository = null; // 使用例如Spring.Net、Provider Pattern來反射生成。(Base專案生成、Ex專案生成,均生成同一個 IUserProfileRepository)
ExUserRepository exUserRepository = new ExUserRepository(userProfileRepository);
IEnumerable<ExUser> exUserCollection = exUserRepository.GetAll();
// Show
this.ShowExUser(exUserCollection);
}
private void ShowExUser(IEnumerable<ExUser> exUserCollection)
{
//.....
}
}
public class ExUser : User
{
// Properties
public string Address
{
get
{
return Convert.ToString(this.Profile["Address"]);
}
set
{
this.Profile["Address"] = value;
}
}
// Constructor
public ExUser()
: base()
{
this.Address = string.Empty;
}
}
public class ExUserRepository
{
// Properties
private readonly IUserProfileRepository _userProfileRepository = null;
// Constructor
public ExUserRepository(IUserProfileRepository userProfileRepository)
{
#region Require
if (userProfileRepository == null) throw new ArgumentNullException();
#endregion
_userProfileRepository = userProfileRepository;
}
// Methods
private ExUser CreateExUser(UserProfile userProfile)
{
#region Require
if (userProfile == null) throw new ArgumentNullException();
#endregion
ExUser exUser = new ExUser();
exUser.UserID = userProfile.UserID;
foreach (string key in userProfile.Keys)
{
exUser.Profile.Add(key, userProfile[key]);
}
return exUser;
}
private UserProfile CreateUserProfile(ExUser exUser)
{
#region Require
if (exUser == null) throw new ArgumentNullException();
#endregion
return exUser.Profile;
}
public void Add(ExUser item)
{
#region Require
if (item == null) throw new ArgumentNullException();
#endregion
_userProfileRepository.Add(this.CreateUserProfile(item));
}
public void Modify(ExUser item)
{
#region Require
if (item == null) throw new ArgumentNullException();
#endregion
_userProfileRepository.Modify(this.CreateUserProfile(item));
}
public void Remove(Guid id)
{
#region Require
if (id == Guid.Empty) throw new ArgumentNullException();
#endregion
_userProfileRepository.Remove(id);
}
public ExUser GetByID(Guid id)
{
#region Require
if (id == Guid.Empty) throw new ArgumentNullException();
#endregion
return this.CreateExUser(_userProfileRepository.GetByID(id));
}
public IEnumerable<ExUser> GetAll()
{
List<ExUser> itemCollection = new List<ExUser>();
foreach (UserProfile userProfile in _userProfileRepository.GetAll())
{
itemCollection.Add(this.CreateExUser(userProfile));
}
return itemCollection;
}
}
}
結語 :
本文範例簡單的說就是,基礎專案的 User與擴展專案的 ExUser,轉為統一的 UserProfile,使用共同的一個IUserProfileRepository進出系統邊界。(*UserProfile有各種的實作方法)
本文介紹的Entity Profile模式,擴展了物件的屬性資料,但其實可以看成,處理了強行別擴展物件進出系統邊界的責任。以此模式為基礎發展,理論上可以設計出能無限擴充屬性資料的應用系統架構。
能以更簡潔的文字與程式碼,傳達出程式設計背後的精神。
真正做到「以形寫神」的境界。