[Architecture] Entity Profile

[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模式,擴展了物件的屬性資料,但其實可以看成,處理了強行別擴展物件進出系統邊界的責任。以此模式為基礎發展,理論上可以設計出能無限擴充屬性資料的應用系統架構。

 

期許自己
能以更簡潔的文字與程式碼,傳達出程式設計背後的精神。
真正做到「以形寫神」的境界。