实体类的变形【1】—— 餐盘原理

时间:2022-04-27
本文章向大家介绍实体类的变形【1】—— 餐盘原理,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

    在亚历山大同学的post里面我说可以让实体类和表不必一一对应,但是并没有详细说明如何来做,也有人想问我是怎么做的,那么我就说一下。先说一个简单一点的,那就是在网页里面显示列表数据的情况,其他的下次再说。我们先来看一个生活中的情况,然后再说程序里面如何来做。

餐盘原理——模糊对应

     餐盘,大家去食堂吃饭的时候,是不是会用一个长方形的餐盘来盛饭和菜呢?长方形的餐盘里有一个大一点的长方形的阁子,可以用来盛饭,当然也可以放馒头、花卷、面条等;有两、到四个个小一点的阁子,可以盛菜;由一个圆形的阁子可以放小碗;还有一个细长的可以放筷子。

     无论食堂做什么饭菜,我们都是用这个餐盘来盛的。这个餐盘既可以放鸡蛋炒黄瓜、烧茄子、黄花鱼还可以放宫保鸡丁等。一个餐盘应对了好多种菜。

     餐盘规定了有几个阁子,阁子里面可以放食物,但是并没有规定阁子里面必须放什么食物,阁子里面到底放什么食物就是一种模糊的对应关系。

     好了让我们回到程序中来,假设我们要仿照博客园的社区来做一个小程序。社区里面有新闻、小组、博文、闪存、博友等内容,假设数据库里面有这几个表:cmt_News_NewsInfo(存放新闻内容)、cmt_Group_topic(小组里面的话题)、cmt_FAQ_Questions(存放博友提问)、cmt_Flash_FlashInfo(存放闪存内容)

     如果现在我们想要做一个社区首页,要如何设置实体类呢?按照我对OO的一知半解,我可能会设计下面这几个类,这几个类都是和表(或者是视图)一一对应的。不管和谁对应,并不是重点。

public class Group_topic  { public string Topic;  //话题名称 public string TopicURL;  //话题的连接地址 public string Group;  //话题所属小组 public string GroupURL;  //小组的连接地址 public string View;   //回应/浏览 public string SendDate;  //话题发表日期 public string Author;  //作者姓名 public string AuthorURL; //作者的连接地址  } public class FlashInfo  { public string Author;  //作者姓名 public string AuthorURL; //作者的连接地址 public string Message;  //闪存的内容 public string SendDate;  //话题发表日期 public string ToAuthor;  //to 作者姓名 public string ToAuthorURL; //to 作者的连接地址  } public class Group_Lesson  { public string GroupName; //小组名称 public string GroupURL; //小组名称 public string GroupImage; //小组名称 public string MembersCount; //成员数量  }

其他的就省略了。

     不知道这么设计对不对,先假设这么设计是对的吧,那么由于属性不同,就需要设计多个不同的实体类,给实体类赋值的部分也要写多个,业务逻辑的部分也要针对各个实体类的属性名称来编写,UI也要根据实体类的属性名称来取值。

我们来看看程序的步骤:

1、定义实体类。有几个“列表”就要定义几个实体类。 2、给实体类赋值。由于是多种实体类,那么给实体类赋值就有点麻烦,不能用一个函数搞定,当然我们可以请来ORM帮忙。但是ORM的使用也并不是很轻松。 3、业务逻辑的处理。依据业务需求对实体类的属性名称来做处理。 4、显示数据。依据页面布局和实体类的属性名称来提取数据。

     这样各个部分都和实体类的属性名称发生了关联(这个就是内容耦合吧?),如果这时候字段名称发生了变化,那么每个部分都要做些修改。而修改的原因仅仅是实体类的属性名称变化了。

     这样设计实体类对吗?面向对象,一切皆为对象,见到猫猫了就 class cat, 见到狗狗了就 class dog,见到新闻就 class News。真的有这么简单吗?面向对象的精华是“抽象”吧?猫和狗可以抽出来一个class Animals,那么这么做抽象的依据是什么呢?往往被忽略了。

     请注意:我们讨论的前提和目的:在网页里面显示列表性质的数据,这个例子的要求:实现社区的首页。

首页里面是最新的新闻、最新的小组话题、最新的问题等。那么我们是不是要根据这个要求来进行一下抽象呢?

要显示最新(最多的、最高的等)的n条数据,有“名称”、连接、点击量、介绍等。那么是不是可以根据这个来抽象呢?

您可能会眼前一亮,对呀,设计一个基类,然后派生出四个子类对应新闻、博文、小组话题等。

比如这样 class WebDataList {}

     这样是抽象了,但是其实还是多种不同的实体类,对上面的步骤不会有什么的改进和帮助。

那么到底要如何来做呢呢?想想上面的餐盘,我们是不是可以设置一个这样的“通用”实体类?(请注意通用的范围:网页里的列表数据的显示)

/// 一般的列表 public struct TitleBase  { /// 0 记录的主键ID public string ID;   // /// 1 链接地址,用于静态页或者URL重写 public string URL;   // /// 2 全部标题 public string AllTitle;  // /// 2 限制字数的标题 public string Title;  // /// 3 发表时间 public string AddedDate; // /// 4 简介内容 public string Introduction; // /// 5 备用1。人气 public string Other1;     // /// 6 备用2。图片路径 public string Other2;     // /// 7 备用3。 public string Other3;     //  }

     这是一个固定的“实体类”,他的属性名称是固定的,这样做有什么优点呢?

1、只需要定义一个实体类就可以了,实体类的数量不会根据网站(列表页面)的扩展而扩展。 2、给实体类赋值的函数只写一个就可以了,不同的列表只需要修改SQL语句即可。 3、由于实体类的属性名称是固定的,这样如果只是字段名称修改了,那么只需要改一下SQL语句即可,其他的代码都不需要修改。

缺点:有优点就会带来点缺点。

1、有浪费的嫌疑,由于属性的数量是固定的,有的时候并不需要这么多,那么多出来属性的就浪费了。 2、需要写一个属性名和字段名的对应关系的说明(约定),各个部分按照这个约定行事。这个应该属于文档的一部分吧。 3、SQL语句的编写有一定的要求:SQL语句里的字段数必须是8个,而且字段的顺序必须要对好。 4、只适合网站的列表型数据的显示,因为一般这样的数据字段比较类似,字段数量也比较少,8个属性可以应对。

代码实现

定义实体类,

实现填充数据的help 定义数据层 定义业务逻辑层 定义UI层

public TitleBase[] LoadTitleBase(int Count,string sql)
        {
            //int Count = 10 ;    //显示最新的10条小组话题
            //string sql = "";

            TitleBase[] tmp = new TitleBase[Count];

            SqlConnection cn = new SqlConnection();
            SqlCommand cm = new SqlCommand (sql,cn);
            cn.Open();

            SqlDataReader dr = cm.ExecuteReader();
            int i = 0;
            while (dr.Read())
            {
                tmp[i].ID = dr[0].ToString();
                tmp[i].URL = dr[1].ToString();
                tmp[i].Title  = dr[2].ToString();
                tmp[i].AddedDate  = dr[3].ToString();
                tmp[i].Introduction  = dr[4].ToString();
                tmp[i].Other1  = dr[5].ToString();
                tmp[i].Other2  = dr[6].ToString();
                tmp[i].Other3  = dr[7].ToString();
 
                i++;
            }

            return tmp;

        }

        /// <summary>
        /// 数据层
        /// </summary>
        /// <returns></returns>
        public TitleBase[] Get_top10_Group_topic()
        {
            //                            ID            URL      Title   AddedDate Introduction  Other1  Other2  Other3
            string sql = "select top 10 TopicURL,GroupURL,Topic,  SendDate,  Group,       View,   Author, AuthorURL from cmt_Group_topic order by SendDate desc "; //SQL语句略
            return  LoadTitleBase(10, sql);
        }

        /// <summary>
        /// 逻辑层
        /// </summary>
        /// <returns></returns>
        public TitleBase[]  Top10_Group_topic()
        {
            TitleBase[] tmp;
            tmp = Get_top10_Group_topic();
            //逻辑处理
            return tmp;
            
        }

        /// <summary>
        /// UI
        /// </summary>
        private void LoadData()
        {
            TitleBase[] Group_topic ;
            Group_topic = Top10_Group_topic();

            //数据绑定
        }

}

简化的写法

private void MyLoadData()
         {
             TitleBase[] Group_topic ;
 
 //                            ID            URL      Title   AddedDate Introduction  Other1  Other2  Other3
  string sql = "select top 10 TopicURL,GroupURL,Topic,  SendDate,  Group,       View,   Author, AuthorURL from cmt_Group_topic order by SendDate desc "; //SQL语句略
  
             Group_topic =  LoadTitleBase(10, sql);
 
 //逻辑处理
 
 //数据绑定
 
         }

直接在.aspx.cs文件里面写上面的代码。

SQL语句的处理。 SQL语句可以放在一个单独的类里面统一管理,也可以放在xml文件里面动态加载。这样是不是变成了传说中的依赖注入呢?