动机 :

一个软件系统的生命周期,必然面临到系统改版的问题。而在系统改版的时候,最常遇到的问题之一是,用户希望增加系统对象的数据字段(例如 : 用户数据增加相片)。常见的做法是把相关的功能,从把整个系统从UI到DB重整(重写?)一遍,让用户希望增加至系统的字段,在系统里实现。

这样的做法,笔者把它称作『修改式程序代码累积』。所谓的修改式程序代码累积是说,藉由修改经过验证、并且正常运作的程序代码与接口来扩充系统。理论上,程序代码经过修改之后,必须重新执行完整的测试。而接口经过修改,使用手册、教育训练等等,常常也必需做同步的更新。可以说是牵一发动全身。

笔者比较喜爱『增加式程序代码累积』。所谓的增加式程序代码累积是说,原有的程序代码、包含接口不做更动,而是增加额外的程序代码附加到系统内来扩充系统。 因为程序代码与接口都没有做过修改,就可以避免修改程序代码所产生的额外工作。但不可避免的,这样的系统在开发初期要花比较大的心力做设计。

本文介绍一个Entity Expansion模式。Entity Expansion模式主要是定义一组,数据对象(Entity)以及边界对象(Repository)的生成、结构、行为模式,用来扩展对象的属性数据。实作这个模式,可以为系统加入增加式程序代码累积的能力。

* 下列文章分别标注段落为01、02只是不想全部写成一个超长段落,不是示意项目必须拆解成两个。

基础平台 :

结构

参与者

Page Shell
-页面的壳层,可以透过设定数据,动态挂载系统页面的系统。

范例程序

Page Shell依照开发平台的不同,会有不同的选择。例如以ASP.NET的平台来说,可以直接套用ASP.NET的页面机制,然后再另外建立一个索引页面,用修改索引页面的方式来达成动态挂载系统页面的需求。

基础项目01 :

结构

参与者

UserManagePage
-User管理页面,提供新增、修改、删除、查询 User的功能。
-使用例如 Spring.Net、Provider Pattern来反射生成 IUserRepositoryFactory。
-使用生成的 IUserRepositoryFactory生成 IUserRepository。
-使用 IUserRepository新增、修改、删除、查询 User。

User
-系统运作使用的数据对象。

IUserRepositoryFactory
-生成 IUserRepository。
-依靠例如 Spring.Net、Provider Pattern来反射生成。

IUserRepository
-数据对象 User进出系统边界的接口。
-提供新增、修改、删除、查询等功能。

范例程序

namespace CLK.EntityExpansion
{public class UserManagePage{// Methodspublic void ShowUser(){// GetDataIUserRepositoryFactory userRepositoryFactory = null; // 使用例如Spring.Net、Provider Pattern来反射生成。(Base专案生成 DefaultUserRepositoryFactory、Ex专案生成 ExpandedUserRepositoryFactory)IUserRepository userRepository = userRepositoryFactory.CreateRepository();IEnumerable<User> userCollection = userRepository.GetAll();// Showthis.ShowUser(userCollection);}private void ShowUser(IEnumerable<User> userCollection){//.....}}public class User{// Constructorpublic User(){this.UserID = Guid.Empty;this.Name = string.Empty;this.Description = string.Empty;}protected User(User item){#region Requireif (item == null) throw new ArgumentNullException();#endregionthis.UserID = item.UserID;this.Name = item.Name;this.Description = item.Description;}// Propertiespublic Guid UserID { get; set; }public string Name { get; set; }public string Description { get; set; }        }public interface IUserRepositoryFactory{// MethodsIUserRepository CreateRepository();}public interface IUserRepository{// Methodsvoid Add(User item);void Modify(User item);void Remove(Guid id);User GetByID(Guid id);IEnumerable<User> GetAll();}
}

基础项目02 :

结构

参与者

DefaultUserRepositoryFactory
-IUserRepositoryFactory的实作
-生成 IUserRepository - SqlUserRepository。

SqlUserRepository
-数据对象 User进出系统边界的接口,IUserRepository的实作。
-依靠 IUserRepositoryFactory生成。
-负责将数据对象User进出SQL数据库。

范例程序

namespace CLK.EntityExpansion
{public class DefaultUserRepositoryFactory : IUserRepositoryFactory{// Methodspublic IUserRepository CreateRepository(){// CreateIUserRepository userRepository = new SqlUserRepository();// Returnreturn userRepository;}}public class SqlUserRepository : IUserRepository{// Methodspublic void Add(User item){// Sql操作...}public void Modify(User item){// Sql操作...}public void Remove(Guid id){// Sql操作...}public User GetByID(Guid id){// Sql操作...return null;}public IEnumerable<User> GetAll(){// Sql操作...return null;}}
}

扩展专案01 :

结构

参与者

ExUserManagePage
-ExUser管理页面,提供新增、修改、删除、查询 ExUser的功能。
-使用例如 Spring.Net、Provider Pattern来反射生成 IExUserRepositoryFactory。
-使用生成的 IExUserRepositoryFactory生成 IExUserRepository。
-使用 IExUserRepository新增、修改、删除、查询 ExUser。

ExUser
-系统运作使用的数据对象。
-继承User并且扩展自己的属性数据。

IUserRepositoryFactory
-生成 IExUserRepository。
-依靠例如 Spring.Net、Provider Pattern来反射生成。

IExUserRepository
-数据对象 ExUser进出系统边界的接口。
-提供新增、修改、删除、查询等功能。

范例程序

namespace CLK.EntityExpansion.Expanded
{public class ExUserManagePage{// Methodspublic void ShowExUser(){// GetDataIExUserRepositoryFactory userRepositoryFactory = null; // 使用例如Spring.Net、Provider Pattern来反射生成。(Base专案生成 DefaultExUserRepositoryFactory、Ex专案生成 ExpandedExUserRepositoryFactory)IExUserRepository userRepository = userRepositoryFactory.CreateRepository();IEnumerable<ExUser> userCollection = userRepository.GetAll();// Showthis.ShowExUser(userCollection);}private void ShowExUser(IEnumerable<ExUser> exUserCollection){//.....}}public class ExUser : User{        // Constructorpublic ExUser(): base(){this.Photo = null;}public ExUser(User item): base(item){#region Requireif (item == null) throw new ArgumentNullException();#endregionthis.Photo = null;}// Propertiespublic byte[] Photo { get; set; }}public interface IExUserRepositoryFactory{// MethodsIExUserRepository CreateRepository();}public interface IExUserRepository{// Methodsvoid Add(ExUser item);void Modify(ExUser item);void Remove(Guid id);ExUser GetByID(Guid id);IEnumerable<ExUser> GetAll();}
}

扩展专案02 :

结构

参与者

DefaultExUserRepositoryFactory
-IExUserRepositoryFactory的实作。
-生成 IUserRepository - SqlUserRepository。
-生成 IExUserSectionRepository - SqlExUserSectionRepository。
-生成 ExUserRepository,传入生成的IUserRepository、IExUserSectionRepository。

ExUserRepository
-数据对象 ExUser进出系统边界的接口,IExUserRepository的实作。
-依靠 DefaultExUserRepositoryFactory生成,接受传入的IUserRepository、IExUserSectionRepository。
-负责数据对象ExUser拆解为 User及ExUserSection。并将使用者对其新增修改删除动作拆解为,User对象进出IUserRepository、ExUserSection物件进出IExUserSectionRepository。
-负责数据对象User及ExUserSection组合为ExUser。并将使用者对其查询动作拆解为,User对象进出IUserRepository、ExUserSection物件进出IExUserSectionRepository。

ExUserSection
-系统运作使用的数据对象,存放ExUser扩充增加的属性数据。

IExUserSectionRepository
-数据对象 ExUserSection进出系统边界的接口。
-提供新增、修改、删除、查询等功能。

SqlExUserSectionRepository
-数据对象ExUserSection 进出系统边界的接口,IUserRepository的实作。
-负责将数据对象 ExUserSection进出SQL数据库。

ExpandedUserRepositoryFactory
-IUserRepositoryFactory的实作。
-生成 IUserRepository - SqlUserRepository。
-生成 IExUserSectionRepository - SqlExUserSectionRepository。
-生成 UserRepositoryDecorator传入生成的IUserRepository、IExUserSectionRepository。

UserRepositoryDecorator
-数据对象 User进出系统边界的接口,IUserRepository的实作。
-依靠 IUserRepositoryFactory生成。
-依靠 ExpandedUserRepositoryFactory生成,接受传入的IUserRepository、IExUserSectionRepository。
-负责将用户对数据对象User新增修改删除查询动作拆解为进出IUserRepository。
-负责数据对象User拆解为 UserId。并将使用者对其删除动作拆解为,ExUserSection对象自IExUserSectionRepository移除。

范例程序

namespace CLK.EntityExpansion.Expanded
{public class ExUserSection{// Propertiespublic Guid UserID { get; set; }public byte[] Photo { get; set; }}public interface IExUserSectionRepository{// Methodsvoid Add(ExUserSection item);void Modify(ExUserSection item);void Remove(Guid id);ExUserSection GetByID(Guid id);}public class SqlExUserSectionRepository : IExUserSectionRepository{public void Add(ExUserSection item){// Sql操作...}public void Modify(ExUserSection item){// Sql操作...}public void Remove(Guid id){// Sql操作...}public ExUserSection GetByID(Guid id){// Sql操作...return null;}}
}
namespace CLK.EntityExpansion.Expanded
{public class DefaultExUserRepositoryFactory : IExUserRepositoryFactory{// Methodspublic IExUserRepository CreateRepository(){// CreateIUserRepository userRepository = new SqlUserRepository();IExUserSectionRepository exUserSectionRepository = new SqlExUserSectionRepository();// Returnreturn new ExUserRepository(userRepository, exUserSectionRepository);}}public class ExUserRepository : IExUserRepository{// Fieldsprivate readonly IUserRepository _userRepository = null;private readonly IExUserSectionRepository _exUserSectionRepository = null;// Constructorpublic ExUserRepository(IUserRepository userRepository, IExUserSectionRepository exUserSectionRepository){#region Requireif (userRepository == null) throw new ArgumentNullException();if (exUserSectionRepository == null) throw new ArgumentNullException();#endregion_userRepository = userRepository;_exUserSectionRepository = exUserSectionRepository;}// Methodspublic void Add(ExUser item){#region Requireif (item == null) throw new ArgumentNullException();#endregion// User_userRepository.Add(item);// ExUserSectionExUserSection exUserSection = new ExUserSection();exUserSection.UserID = item.UserID;exUserSection.Photo = item.Photo;_exUserSectionRepository.Add(exUserSection);}public void Modify(ExUser item){#region Requireif (item == null) throw new ArgumentNullException();#endregion// User_userRepository.Modify(item);// ExUserSectionExUserSection exUserSection = new ExUserSection();exUserSection.UserID = item.UserID;exUserSection.Photo = item.Photo;_exUserSectionRepository.Modify(exUserSection);}public void Remove(Guid id){#region Requireif (id == Guid.Empty) throw new ArgumentNullException();#endregion// User            _userRepository.Remove(id);// ExUserSection_exUserSectionRepository.Remove(id);}public ExUser GetByID(Guid id){#region Requireif (id == Guid.Empty) throw new ArgumentNullException();#endregion// User    User user = _userRepository.GetByID(id);if (user == null) return null;// ExUserSectionExUserSection exUserSection = _exUserSectionRepository.GetByID(id);if (exUserSection == null) return new ExUser(user);// ExUserExUser exUser = new ExUser(user);exUser.Photo = exUserSection.Photo;return exUser;}public IEnumerable<ExUser> GetAll(){// ResultList<ExUser> exUserList = new List<ExUser>();// User    foreach (User user in _userRepository.GetAll()){// ExUserSectionExUserSection exUserSection = _exUserSectionRepository.GetByID(user.UserID);if (exUserSection == null){exUserList.Add(new ExUser(user));continue;}// ExUserExUser exUser = new ExUser(user);exUser.Photo = exUserSection.Photo;exUserList.Add(exUser);}                      // Returnreturn exUserList;}}
}
namespace CLK.EntityExpansion.Expanded
{public class ExpandedUserRepositoryFactory : IUserRepositoryFactory{// Methodspublic IUserRepository CreateRepository(){// CreateIUserRepository userRepository = new SqlUserRepository();IExUserSectionRepository exUserSectionRepository = new SqlExUserSectionRepository();// Returnreturn new UserRepositoryDecorator(userRepository, exUserSectionRepository);}}public class UserRepositoryDecorator : IUserRepository{// Fieldsprivate readonly IUserRepository _userRepository = null;private readonly IExUserSectionRepository _exUserSectionRepository = null;// Constructorpublic UserRepositoryDecorator(IUserRepository userRepository, IExUserSectionRepository exUserSectionRepository){#region Requireif (userRepository == null) throw new ArgumentNullException();if (exUserSectionRepository == null) throw new ArgumentNullException();#endregion_userRepository = userRepository;_exUserSectionRepository = exUserSectionRepository;}// Methodspublic void Add(User item){#region Requireif (item == null) throw new ArgumentNullException();#endregion// User_userRepository.Add(item);}public void Modify(User item){#region Requireif (item == null) throw new ArgumentNullException();#endregion// User_userRepository.Modify(item);}public void Remove(Guid id){#region Requireif (id == Guid.Empty) throw new ArgumentNullException();#endregion// User            _userRepository.Remove(id);// ExUserSection_exUserSectionRepository.Remove(id);}public User GetByID(Guid id){#region Requireif (id == Guid.Empty) throw new ArgumentNullException();#endregion// User    User user = _userRepository.GetByID(id);// Returnreturn user;}public IEnumerable<User> GetAll(){// ResultIEnumerable<User> userList = null;// User    userList = _userRepository.GetAll();// Returnreturn userList;}}
}

结语 :

本文范例简单的说就是,当基础项目与扩展项目都建立完毕。在原本基础项目的管理页面建立User对象,在扩展项目的ExUser管理页面也可以查询到新增的ExUser(内容为User数据,ExUser扩展的属性数据为默认值)。当在扩展项目删除ExUser时,基础项目内的User也会同时被删除。

本文介绍的Entity Expansion模式,看起来只是扩展了对象的属性数据,但其实可以看成,处理了强型别扩展对象进出系统边界的责任。以此模式为基础发展,理论上可以设计出能无限延伸的应用系统架构。

转载于:https://www.cnblogs.com/clark159/archive/2011/10/10/2205136.html

[Architecture Pattern] Entity Expansion相关推荐

  1. Software Architecture Pattern(Mark Richards)笔记

    软件架构模式 缺少规范架构的程序通常会变得紧耦合.脆弱.难以更改,缺少清晰的发展方向和愿景.这本小书用50多页介绍了常用的5种常见架构模式,相信不管是大牛还是萌新都会有所收获,特别是对我这种偏爱系统设 ...

  2. Design Pattern: Observer Pattern

    1. Brief 一直对Observer Pattern和Pub/Sub Pattern有所混淆,下面打算通过这两篇Blog来梳理这两种模式.若有纰漏请大家指正. 2. Use Case 首先我们来面 ...

  3. 软件架构之分层模式(Layered Architecture)

    分层模式是最通用的架构,也被叫做N层架构模式(n-tier architecture pattern).这也是Java EE应用经常采用的标准模式.基本上都知道它.这种架构模式非常适合传统的IT通信和 ...

  4. understand软件使用教程

    源代码阅读工具(Scientific Toolworks Understand)的特色 1.支持多语言:Ada, C, C++, C#, Java, FORTRAN, Delphi, Jovial, ...

  5. 何时使用领域驱动设计

    何时使用领域驱动设计?其实当你的应用程序架构设计是面向业务的时候,你已经开始使用领域驱动设计了.领域驱动设计既不是架构风格(Architecture Style),也不是架构模式(Architectu ...

  6. 记录一个android性能优化宝藏级总结

    发现一个android性能优化文章宝藏级总结,太赞了,感谢大佬的无私奉献总结,防止丢失,在此记录一下 传送门 复制一些目录,增加一些篇幅{嘻嘻} 优化心得和经验 抖音 Android 性能优化系列:启 ...

  7. Find-Sec-Bugs 漏洞范例

    第一章 Find-sec-bugs简介 插件介绍: Find-Sec-Bugs 是一款本地 bug 扫描插件 "FindBugs-IDEA" 的 Java 安全漏洞规则扩展库,它支 ...

  8. 架构模式-VIPER

    架构模式-VIPER iOS架构模式,可参考如下的文章: iOS 架构模式–解密 MVC,MVP,MVVM以及VIPER架构 浅谈 MVC.MVP 和 MVVM 架构模式 iOS VIPER架构实践( ...

  9. 系统分析师 常用英文词汇

    feasibility analysis可行性分析 fishbone diagram鱼骨图 prelimminary investigation初步调查 SMP对称多处理 Symmetrical Mu ...

最新文章

  1. 打工人,打工魂,抽终身会员,成为人上人!
  2. 11: facebook原生登录
  3. FAQ系列 | 如何保证主从复制数据一致性(转)
  4. 使用PowerShell调用MTools分析MongoDB性能并发送邮件
  5. mysql isolation level_MySQL数据库事务隔离级别(Transaction Isolation Level)
  6. 单片机c语言实验,单片机实验C语言编程.doc
  7. 在删除一个指针之后,一定将该指针设置成空指针(即在delete *p之后一定要加上: p=NULL)...
  8. OpenCV学习笔记(十一):阈值化:threshold(),adaptivethreshold()
  9. java observable 使用_如何使用rxjava2取消Observable.timer?
  10. Android 性能优化案例
  11. Javascript第五章改变CSS样式节点两种方法,制作导航背景切换效果第十课
  12. VSCode下载与安装
  13. Google Chrome 浏览器翻译失败解决办法
  14. 怀旧服服务器一般什么时候维护,魔兽世界怀旧服9月16日重启维护结束时间 9.16怀旧服登录不了游戏解决方法_蚕豆网新闻...
  15. 智库说 | 杨宁:从城市管理走向城市治理 大数据将发挥更大作用
  16. Linux学习之Kali制作简单的Windows的木马,创建后门
  17. Daily English(每日一句)
  18. 时光老去,远了年少的我
  19. linux远程可视化
  20. 牛顿法和割线法方程求根(C语言)

热门文章

  1. 计算机网络中的交换技术
  2. 算法时间复杂度分析专题一(帮助快速解题)
  3. 双联通分量求简单环(Educational Codeforces Round 42: F. Simple Cycles Edges)
  4. bzoj 1058: [ZJOI2007]报表统计(set+multiset)
  5. bzoj 1637: [Usaco2007 Mar]Balanced Lineup
  6. Java 绘制艺术图案
  7. C++ STL slice()函数的正确打开方式 带详细注释实例讲解
  8. 吴恩达神经网络和深度学习-学习笔记-15-局部最优
  9. 文档协作编辑 ONLYOFFICE 部署和使用教程
  10. 模拟计算机怎么做,如何为具有独立模拟输出的计算机或音频系统制作8通道放大器...