业务接口+UI层的设计(基于Castle实现的Repository)

Repository层设计的文章见:【http://www.cnblogs.com/yomho/p/3297042.html

  一、概要设计

上面Reposity 应该为 Repository

特此更正,也不打算作图更正了。

  二、业务Server层

业务层Server是承Repository层,启UI层的重要层,

UI层的数据和Repository层的数据传递必须经过它

业务层的扩展非常必要

所以采用IServer<TEntity>的设计方式

接口设计如下:

 1 namespace Yom.NFramework2_0
2 {
3 public interface IServer<TEntity, TPrimaryKey>
4 where TEntity : IEntity
5 where TPrimaryKey : IComparable
6 {
7 TEntity FindBy(TPrimaryKey primaryKey);
8 IEnumerable<TEntity> FindAll();
9 IEnumerable<TEntity> FindAll<TWhere>(TWhere[] where) where TWhere : IWhere;
10 IEnumerable<TEntity> FindAll<TWhere, TOrder>(TWhere[] where, TOrder[] order)
11 where TWhere : IWhere
12 where TOrder : IOrder;
13 IEnumerable<TEntity> FindAll<TWhere, TOrder>(int pageIndex, int pageSize, TWhere[] where, TOrder[] order, out int count)
14 where TWhere : IWhere
15 where TOrder : IOrder;
16 void Add(TEntity entity);
17 void Delete(TEntity entity);
18 void DeleteAll();
19 void DeleteAll<TWhere>(TWhere[] where) where TWhere : IWhere;
20 void DeleteAll(string where);
21 void DeleteAll(IEnumerable<TPrimaryKey> pkValues);
22 void Update(TEntity entity);
23 bool Exists(TPrimaryKey primaryKey);
24
25 TPrimaryKey PrimaryKeyPropertyName
26 {
27 get;
28 }
29 }
30 }

Server层和Repository的接口设计大同小异

大同:方法大致相同

小异:实现方式不同,Server是IServer<TEntity>,Repository是IRepository,Server的如此设计是为了业务扩展。

其中Server层要多了一个获取主键属性名称的方法。

Server层依附Repository的实现如下:

 1 namespace Yom.NFramework2_0
2 {
3 public abstract class ISinglePrimaryKeyServer<TEntity> : IServer<TEntity, String>
4 where TEntity : IEntity
5 {
6 #region IServer<TEntity,string> 成员
7
8 public TEntity FindBy(string primaryKey)
9 {
10 return RepositoryFactory.Instance.FindBy<TEntity>(primaryKey);
11 }
12
13 public IEnumerable<TEntity> FindAll()
14 {
15 return RepositoryFactory.Instance.FindAll<TEntity>();
16 }
17 public IEnumerable<TEntity> FindAll<TWhere>(TWhere[] where) where TWhere : IWhere
18 {
19 return RepositoryFactory.Instance.FindAll<TEntity>(where as IWhere[]);
20 }
21 public IEnumerable<TEntity> FindAll<TWhere, TOrder>(TWhere[] where, TOrder[] order)
22 where TWhere : IWhere
23 where TOrder : IOrder
24 {
25 return RepositoryFactory.Instance.FindAll<TEntity>(where as IWhere[], order as IOrder[]);
26 }
27 public IEnumerable<TEntity> FindAll<TWhere, TOrder>(int pageIndex, int pageSize, TWhere[] where, TOrder[] order, out int count)
28 where TWhere : IWhere
29 where TOrder : IOrder
30 {
31 return RepositoryFactory.Instance.FindAll<TEntity>(pageIndex, pageSize, where as IWhere[], order as IOrder[], out count);
32 }
33
34 public void Add(TEntity entity)
35 {
36 RepositoryFactory.Instance.Add<TEntity>(entity);
37 }
38
39 public void Delete(TEntity entity)
40 {
41 RepositoryFactory.Instance.Delete<TEntity>(entity);
42 }
43
44 public void DeleteAll()
45 {
46 RepositoryFactory.Instance.DeleteAll<TEntity>();
47 }
48
49 public void DeleteAll<TWhere>(TWhere[] where)
50 where TWhere : IWhere
51 {
52 RepositoryFactory.Instance.DeleteAll<TEntity>(where as IWhere[]);
53
54 }
55 public void DeleteAll(string where)
56 {
57 RepositoryFactory.Instance.DeleteAll<TEntity>(where);
58 }
59
60 public void DeleteAll(IEnumerable<string> pkValues)
61 {
62 RepositoryFactory.Instance.DeleteAll<TEntity>(pkValues);
63 }
64
65 public void Update(TEntity entity)
66 {
67 RepositoryFactory.Instance.Update<TEntity>(entity);
68 }
69
70 public bool Exists(string primaryKey)
71 {
72 return RepositoryFactory.Instance.Exists<TEntity>(primaryKey);
73 }
74
75 public abstract string PrimaryKeyPropertyName
76 {
77 get;
78 }
79 #endregion
80 }
81 }

当到用特定的ORM扩展的时候

只需要实现

1 public abstract string PrimaryKeyPropertyName
2 {
3 get;
4 }

就可以了

用Castle实现如下

 1 namespace Yom.NFramework2_0.CastleExtend
2 {
3 public class SinglePrimaryKeyServerBase<TEntity> : Yom.NFramework2_0.ISinglePrimaryKeyServer<TEntity>
4 where TEntity : EntityBase
5 {
6 string GetSinglePrimaryKeyName() {
7 System.Reflection.PropertyInfo[] pis = typeof(TEntity).GetProperties();
8 if (pis != null && pis.Length > 0) {
9 object[] customAttributes;
10 foreach (System.Reflection.PropertyInfo pi in pis) {
11 customAttributes = pi.GetCustomAttributes(typeof(Castle.ActiveRecord.PrimaryKeyAttribute), true);
12 if (customAttributes != null && customAttributes.Length > 0) {
13 string result = (customAttributes[0] as Castle.ActiveRecord.PrimaryKeyAttribute).Column;
14 if (!string.IsNullOrEmpty(result)) {
15 return result;
16 }
17 return pi.Name;
18 }
19 }
20 }
21 return null;
22 }
23
24 public override string PrimaryKeyPropertyName
25 {
26 get { return GetSinglePrimaryKeyName(); }
27 }
28 }
29 }

这样一个完整的基于Castle的ServerBase就准备好了

  三、组合控件UI层

UI层一般有List和Edit这2个常用的控件

这2个控件是SkinnedControlBase的子类

在UI的设计的时候,实现了SkinnedControlBase控件

大家也许想特想知道这控件有什么功能

其实这个控件是实现框架里UI和组装层(实际就是项目)分离的重要控件

这个控件的设计思想请见【http://www.cnblogs.com/yomho/archive/2013/03/10/2953132.html

简单说就是:

UI的业务逻辑和表现数据的HTML代码(html代码写在项目里)完全分离

组合控件分为自定义控件和用户控件两个部分:

1、自定义控件封装后台代码(负责后台操作);

2、用户控件负责前台HTML代码(实现布局和样式以及客户端验证)。

在用aspx页面承载组合控件时候,会结合组合控件中自定义控件的后台逻辑代码和用户控件的Html代码展示数据给客户操作。

这种分离是约定下分离的,就像MVC里面视图和控制器名称的约定一样,

当然也可以个性化配置,实现特定的开发的目录结构,

就像MVC里的Area的设计概念,可以根据项目,对控制器和视图的映射路径进行个性化配置

虽然SkinnedControlBase有点像MVC的思想,但是却完全不是这种MVC概念。

  四、Project项目的功能模块的组装

实现项目的时候,需要费力开发的层次有:Entity层和Server层以及UI层.

这三个层次开发的时候是有顺序的:按Entity - > Server - > UI 层的顺序逐步细化

当有了UI层,比如有XXX/List.cs这个控件后,就可以开始实施Views/XXX/Lit.ascx这个控件了

XXX/List.cs和Views/XXX/Lit.ascx是相互绑定的:业务逻辑在UI层实现,对应表现数据的Html代码就在ascx里表现

真正加载数据的时候是在aspx里放组合控件

说了这么多,大家一定和头疼

下面给出一个简单的实现样例,比如我要实现部门的增删查改:

先Entity: YOM_DEPARTMENT : Yom.NFramework2_0.CastleExtend.EntityBase

然后Server:YOM_DEPARTMENTServer : Yom.NFramework2_0.CastleExtend.ServerBase<Yom.WbTest.Entity.YOM_DEPARTMENT.YOM_DEPARTMENT>

最后2个UI:

List

 1 namespace Yom.WbTest.UI.YOM_DEPARTMENT
2 {
3 public class List : Yom.NFramework2_0.CastleExtend.Web.WebForm.UI.List.SinglePrimaryKey.CustomSkinnedListBase<Yom.WbTest.Entity.YOM_DEPARTMENT.YOM_DEPARTMENT , Server.YOM_DEPARTMENT.YOM_DEPARTMENTServer>
4 {
5 protected override Yom.NFramework2_0.IWhere[] Where
6 {
7 get {
8 return new NFramework2_0.IWhere[] {
9 new Yom.NFramework2_0.CastleExtend.WhereBase(){ Instance=Yom.NFramework2_0.CastleExtend.WhereBase.Like(this.searchObject["DEPARTMENT_NAME"].PropertyName,this.searchObject["DEPARTMENT_NAME"].Value.ToString(),NHibernate.Expression.MatchMode.Anywhere)}
10 };
11 }
12 }
13 }
14 }

Edit

1 public class Edit : Yom.NFramework2_0.CastleExtend.Web.WebForm.UI.Edit.CustomSkinnedEditBase<Yom.WbTest.Entity.YOM_DEPARTMENT.YOM_DEPARTMENT,Yom.WbTest.Server.YOM_DEPARTMENT.YOM_DEPARTMENTServer>
2 {
3 protected override bool IsValid(out string msg)
4 {
5 return base.IsValid(out msg);
6 }
7 }

其中IsValid负责服务器端的数据验证,如果返回False则不会执行保存操作。

在真正做项目的时候,按照约定排版如下:

Edit.ascx

 1 <%@ Control Language="C#" AutoEventWireup="true" %>
2
3 <table>
4
5 <tr>
6 <td style=" width:10%; white-space:nowrap">部门名称:</td>
7 <td>
8 <asp:TextBox ID="DEPARTMENT_NAME" runat="server" CssClass="input"></asp:TextBox></td>
9 </tr>
10 <tr>
11 <td style=" width:10%; white-space:nowrap">部门编号:</td>
12 <td>
13 <asp:TextBox ID="DEPARTMENT_CODE" runat="server" CssClass="input"></asp:TextBox></td>
14 </tr>
15 <tr>
16 <td style=" width:10%; white-space:nowrap">排序:</td>
17 <td>
18 <asp:TextBox ID="ORDER_ID" runat="server" Text="0" CssClass="input"></asp:TextBox></td>
19 </tr>
20 <tr>
21 <td style=" width:10%; white-space:nowrap">部门描述:</td>
22 <td>
23 <asp:TextBox ID="DEPARTMENT_DESC" runat="server" TextMode="MultiLine" CssClass="textarea"></asp:TextBox></td>
24 </tr>
25 <tr>
26 <td style=" width:10%; white-space:nowrap">是否禁用:</td>
27 <td>
28 <asp:RadioButtonList ID="IS_DISABLED" runat="server"
29 RepeatDirection="Horizontal" RepeatLayout="Flow">
30 <asp:ListItem Value="1">是</asp:ListItem>
31 <asp:ListItem Selected="True" Value="0">否</asp:ListItem>
32 </asp:RadioButtonList>
33 </td>
34 </tr>
35 </table>
36 <asp:Button ID="bSubmit" runat="server" Text="保存" /><input type="button" value="返回" onclick="window.location='List.aspx'" />

List.ascx(实现了点击创建时间,升降开关式排序功能)

 1 <%@ Control Language="C#" AutoEventWireup="true" %>
2 <script type="text/javascript" src="../../Scripts/jquery-1.4.1.min.js"></script>
3 <asp:Panel ID="pSearcher" runat="server">
4 部门名称:
5 <asp:TextBox ID="DEPARTMENT_NAME" runat="server" PropertyName="DEPARTMENT_NAME"></asp:TextBox><asp:Button
6 ID="btnSearch" runat="server" Text="搜索" />
7 </asp:Panel>
8 <div style=" display:block;"><a href="Edit.aspx">新增</a></div>
9 <asp:Repeater ID="lvList" runat="server">
10
11 <HeaderTemplate>
12 <table class="gridview" border="0" cellpadding="0" cellspacing="1" width="100%">
13 <tr>
14 <th><input type="checkbox" title="全选/全消" onclick="$(':checkbox.cbSelectItem').attr('checked',$(this).attr('checked'))" /></th>
15 <th>
16 部门名称</th><th>部门编号</th><th>部门描述</th><th><asp:LinkButton ID="LinkButton4" runat="server" CommandName="Order" CommandArgument="CREATE_DATE">创建时间</asp:LinkButton></th><th>操作</th>
17 </tr>
18 </HeaderTemplate>
19 <ItemTemplate>
20 <tr>
21 <th><%# string.Format("<input type=\"checkbox\" name=\"cbSelectItem\" class=\"cbSelectItem\" value=\"{0}\" />", Eval("DEPARTMENT_ID"))%></th>
22 <td style=" text-align:center"><%# Eval("DEPARTMENT_NAME")%></td>
23 <td style=" text-align:center"><%# Eval("DEPARTMENT_CODE")%></td>
24 <td style=" text-align:center"><%# Eval("DEPARTMENT_DESC")%></td>
25
26 <td style=" text-align:center"><%# string.Format("{0:yyyy-MM-dd}", Convert.ToDateTime(Convert.ToString(Eval("CREATE_DATE"))))%></td>
27 <td style=" text-align:center">
28 <a href="Edit.aspx?id=<%# Eval("DEPARTMENT_ID")%>">编辑</a>|<a href="Edit.aspx?action=delete&id=<%# Eval("DEPARTMENT_ID")%>" onclick="return confirm('确定要删除吗?')">删除</a></td>
29 </tr>
30 </ItemTemplate>
31 <FooterTemplate>
32 </table>
33 </FooterTemplate>
34 </asp:Repeater>

其中Edit.ascx 和List.ascx 不涉及后台代码和任何业务逻辑,可以完全交给美工

如果设计和开发的时候约定好,美工可先行开发Edit.ascx 和List.ascx

下面是aspx页面承载组装控件:

Edit.aspx

<%@ Page Language="C#" AutoEventWireup="true" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<yom:YOM_DEPARTMENT.Edit ID="edit" runat="server">
</yom:YOM_DEPARTMENT.Edit>
</div>
</form>
</body>
</html>

List.aspx

 1 <%@ Page Language="C#" AutoEventWireup="true" %>
2
3 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
4
5 <html xmlns="http://www.w3.org/1999/xhtml">
6 <head runat="server">
7 <title></title>
8 </head>
9 <body>
10 <form id="form1" runat="server">
11 <div>
12 <yom:YOM_DEPARTMENT.List ID="list" runat="server">
13 </yom:YOM_DEPARTMENT.List>
14
15 </div>
16 </form>
17 </body>
18 </html>

 有些细心的朋友可能已经发现:

无论是ascx还是aspx页面都没有code behind的cs文件

这个就和MVC2里aspx和ascx页面的作用一样了

只作为Html的承载文件,并没有什么cs文件去写这些文件的后台代码

否则无法实现后台代码和前台代码分离

  五、总结

1、框架的设计可以很好的支持技术开发人员和美工的分工,且美工知道表结构的情况下可以先行开发;

2、模块化组装的开发模式,在框架成熟的情况下,可以避免页面业务逻辑复杂化,减少bug的出现;

3、开发流程化,减少组织代码的复杂性

4、规范了编程的代码,新人在熟悉后,可以快速进入开发和维护旧项目的状态;

5、换一个UI层和一种Project,可以快速进行项目类型的转换。

  六、关于框架

1、框架的重构,难免有bug未发现,所以还得经过一些项目的开发测试;

2、框架现在只封装了asp.net Webform的开发,后续将接入Winform和MVC等的开发模块;

3、框架没有接入缓存层,所以并不适合百万大数据的项目开发,目前只能应付一些数据量不大的项目;

4、易用性方面解决了旧框架的弊端,有没有新的弊端还需要后续的使用测试。

 
 

业务接口+UI层的设计(基于Castle实现的Repository)的更多相关文章

  1. 【Yom框架】漫谈个人框架的设计之三:业务接口+UI层的设计(基于Castle实现的Repository)

    Repository层设计的文章见:[http://www.cnblogs.com/yomho/p/3297042.html]   一.概要设计 上面Reposity 应该为 Repository 特 ...

  2. 新的IRepository接口+搜索和排序解耦(+基于Castle实现)

    新的IRepository接口+搜索和排序解耦(+基于Castle实现) 经过了上篇IRepository和IRepository<T>的讨论[文章地址为:http://www.cnblo ...

  3. 【Yom框架】漫谈个人框架的设计之二:新的IRepository接口+搜索和排序解耦(+基于Castle实现)

    经过了上篇IRepository和IRepository<T>的讨论[文章地址为:http://www.cnblogs.com/yomho/p/3296759.html] 我选择了IRep ...

  4. 【DDD】领域驱动设计实践 —— UI层实现

    前面几篇blog主要介绍了DDD落地架构及业务建模战术,后续几篇blog会在此基础上,讲解具体的架构实现,通过完整代码demo的形式,更好地将DDD的落地方案呈现出来.本文是架构实现讲解的第一篇,主要 ...

  5. 自动化测试 接口自动化及UI自动化测试平台设计演示

    接口自动化及UI自动化测试平台设计演示   by:授客  QQ:1033553122 欢迎加入全国软件测试交流qq群:7156436 大家好,我是授客. 本视频意在分享个人,基于Python,Djan ...

  6. Spring.NET在MVC中实现业务层和UI层解耦

    最近在项目中用到了Spring.NET,使用它来实现业务层和UI层解耦.使用过程中难免遇到问题,现把遇到的一些问题整理出来,留作笔记. 使用的开发工具是vs2017,.netframework 4.6 ...

  7. SSM框架学习之高并发秒杀业务--笔记3-- Service层

    上一节中已经包DAO层编写完成了,所谓的DAO层就是所有和数据访问的部分都应该放在这个层里,它负责与数据库打交道.对于一个web项目来说,大概由这几部分组成: 1. 前台的显示层. 2. 分发处理请求 ...

  8. SSM框架学习之高并发秒杀业务--笔记2-- DAO层

    上节中利用Maven创建了项目,并导入了所有的依赖,这节来进行DAO层的设计与开发 第一步,创建数据库和表. 首先分析业务,这个SSM匡济整合案例是做一个商品的秒杀系统,要存储的有:1.待秒杀的商品的 ...

  9. J2EE中MVC的各层的设计原则及其编写注意事项

    总结了下J2EE的MVC模式开发原则,很多细节处理好了是很有利于开发与维护的. 下面就从各层说起. 视图层 主要是客户端的显示,主要是JSP和HTML,随着Web的不断发展,许多基于Javascrip ...

随机推荐

  1. oracle_体系结构图_逻辑结构图

    1.oracle 的体系结构图  重要!!! 2.oracle的逻辑结构图

  2. 了解你的家公家IP

          我们总是在不在家的时候,须要訪问我们的电脑或设备,因为大多数人拥有来自ISP的动态IP,我们能够做一个小型设备来给我们的Android手机发送一个简单的通知,这样我们就能够总有IP用了,有 ...

  3. c# 官方命名规则

    官方的哦. https://msdn.microsoft.com/zh-cn/library/vstudio/ff926074(v=vs.110).aspx

  4. github basic usage in windows

    1. create a new accout, create orginazation, create repo 2. install git in your local pc Note: you c ...

  5. HDU 4791 &amp; ZOJ 3726 Alice&#39;s Print Service (数学 打表)

    题目链接: HDU:http://acm.hdu.edu.cn/showproblem.php?pid=4791 ZJU:http://acm.zju.edu.cn/onlinejudge/showP ...

  6. asp.net 给按钮 增加事件

    一个页面,有查询,审核,删除,取消审核 按钮,每次结尾 处都要 调用 Initdata方法,重新刷新数据 繁琐哇,我的解决方法是 protected void Page_Load(object sen ...

  7. linux 多个源文件在编译时会产生一个目标文件

    obj-m := target.o target-objs :=  src1.o src2.o src3.o 版权声明:本文博客原创文章.博客,未经同意,不得转载.

  8. Linux下tomcat管理查看控制台|杀死tomcat进程

    查看控制台 # tail -f catalina.out 脚本执行权限chmod u+x *.sh #看是否已经有tomcat在运行了 ps -ef |grep tomcat #如果有,用kill; ...

  9. CSS3实战开发:使用CSS3实现photoshop的过滤效果

    原文:CSS3实战开发:使用CSS3实现photoshop的过滤效果 我们知道,使用Photoshop来调整图像的亮度和对比度,或者将图片转化为灰度等等是很常见的功能.今天我将给大家介绍几个新特性,我 ...

  10. 清除css、javascript及背景图在浏览器中的缓存

    在实际项目开发过过程中,页面是上传到服务器上的.而为了减少服务器的压力,让用户少加载,浏览器会将图片.css.js缓存到本地中,以便下次访问网站时使用.这样做不仅减少了服务器的压力,并且也减少了用户的 ...