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


    业务接口+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=" 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=" 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=" 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=" 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=" 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、易用性方面解决了旧框架的弊端,有没有新的弊端还需要后续的使用测试。

     
     
  • 相关阅读:
    【Codeforces 349B】Color the Fence
    【Codeforces 459D】Pashmak and Parmida's problem
    【Codeforces 467C】George and Job
    【Codeforces 161D】Distance in Tree
    【Codeforces 522A】Reposts
    【Codeforces 225C】Barcode
    【Codeforces 446A】DZY Loves Sequences
    【Codeforces 429B】Working out
    【Codeforces 478C】Table Decorations
    【Codeforces 478C】Table Decorations
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3308935.html
Copyright © 2020-2023  润新知