编程基础系列--之--泛型基础,检索枚举,以及在抽象工厂中的使用
万丈高楼平地起,基础是重中之重,虽说基础在生产环境下作用并不大,但是扎实的基础是你不断学习的保障。今天继续探讨基础--泛型。
刚刚步入社会,开始自己的第一份工作,在工作中遇到这样一个业务场景:我需要将枚举字段存到数据库中,数据库是一位大佬设计的,枚举字段是英文,对应的值是int类型,我要在界面上显示的值却要是中文,这个问题其实并不难,按照我一开始的思路,我只需要根据数据库中存的值查询出来,必要的时候手动将英文转换成中文就可以了。但是在实际做项目的过程中才发现。这样设计的程序太死板而且特别麻烦。有没有好的解决方案呢?
答案是有的,枚举字段在定义的时候是可以设置一些文字描述的。我们可以将文字描述设置成中文,往数据库中存储的时候存它的中文描述就可以了,枚举字段起的作用就变成了强制用户选择时只能选这几个字段。而且后期如果需要添加新的选项,只需要修改枚举字段就可以了,代码是不需要改动的。
好了,说完了业务需求,步入今天的正题:泛型。
你可能会疑惑,说着说着枚举字段怎么会跳到泛型上去了?你Y的脑子有泡吧。不要着急,听我慢慢说
首先介绍一下泛型,引用一下官方定义:
//定义一个泛型类 public class Generic <T>{ public void show(T t) { System.out.println(t); } }
//泛型类的使用 Generic<String> g1 = new Generic<String>(); g1.show("林青霞"); Generic<Integer> g2= new Generic<Integer>(); g2.show(30); Generic<Boolean> g3=new Generic<Boolean>(); g3.show(true);
代码肯定会在某些地方看到过,思想都是一样的。我们的泛型类里面没有定义具体要打印的类型,只是有一个T作为要操作的类型,我们在实际使用的时候对这个类进行了一些初始化,传入了一个我们要操作的类型。运行一下就会发现,你传入什么类型值,函数打印的就是什么类型的值。我们如果不使用泛型,那么定义类的时候就有可能需要为每个类型定义一个重载函数才能实现我们现在要实现的这个小功能。
这就是基本的泛型。ok,说到这里简单的总结一下,泛型在我的理解里边是对操作的一种抽象和整理,操作大致相同的我们可以用一个泛型来处理,使用的时候只需要根据需求传不同的类型就可以了,降低了代码的冗余,提高了编码的效率。
ok。说完了简单的泛型介绍,我们来说一下怎么将枚举字段转换成list集合。下面的代码我将使用C#的编码规则,因为我本身是搞.net的,所以对C#语法比对Java要熟悉,再次强调,我是小白!!!
首先我们定义一个实体类,我们需要将从枚举中取出来的值放在实体类中,方便往前端界面传参
/// <summary> /// 枚举遍历实体内部类 /// </summary> public class EnumberEntity { /// <summary> /// 枚举的描述 /// </summary> public string Desction { get; set; } /// <summary> /// 枚举的名称 /// </summary> public string EnumName { get; set; } /// <summary> /// 枚举对象的值 /// </summary> public int EnvmValue { get; set; } }
接下来我们用泛型的思想,反射的方法来取枚举字段值,为什么要用泛型,因为我们要做的是一个可以被很多枚举使用的方法,而不知单独为这一个枚举写一个方法,如果单独为每一个枚举都写这样一个方法,代码冗余高,重用率不高,不是一个好的代码
public List<EnumberEntity> EnumToList<T>() { //思路很简单,定义一个内部实体类,将枚举中的值赋值到这个实体类中进行传参 //实例化自定义的内部实体类 List<EnumberEntity> list = new List<EnumberEntity>(); //开始遍历要查询的枚举 foreach (var e in Enum.GetValues(typeof(T))) { //实例化实体类 EnumberEntity m = new EnumberEntity(); object[] objArr = e.GetType().GetField(e.ToString()).GetCustomAttributes(typeof(DescriptionAttribute), true);//GetCustomAttributes这个方法是通过反射的方式来获取枚举的值,DescriptionAttribute:指定属性或事件的说明 if (objArr != null && objArr.Length > 0) { DescriptionAttribute da = objArr[0] as DescriptionAttribute; m.Desction = da.Description; } m.EnvmValue = Convert.ToInt32(e); m.EnumName = e.ToString(); //将查询出来的值加载到集合里面去 list.Add(m); } return list; }
对,忘记说了,我的代码是基于MVC模式,这些代码是在控制器里写的。
对于这段代码我就不做详细的介绍了,思想蛮简单的
/// <summary> /// 测试枚举 /// </summary> public enum Test { 男=0, 女=1 } public ActionResult aaa() { EnumToList<Test>(); return View(); }
这是我在生产环境下做的写的一部分用到泛型的方法,接下来介绍一下我对设计模式的理解。下面的代码将不是生产模式下的代码,我的级别还不到可以管理整个项目,这里只是我自己闲着没事研究的。本着技术共享的原则,跟大家探讨一下。
首先说一下我对设计模式的理解:在我的理解中,设计模式是用来解耦的,所谓的解耦就是减少上层对底层的依赖,那么为什么要有解耦呢?因为懒。。。。。。。
想象一个场景,你刚做完一个需求,突然,产品经理跟你说要改需求,这里小小的改动一下,可能只是添加一个功能,但是因为你的代码对下层的依赖非常严重,你需要改上层表现层,甚至连底层的数据访问层都需要改,只是添加一个很简单的功能,却需要三层全部都需要改,是不是一件很可怕的事?
所以需要解耦~
而设计模式中最基本的就是对方法对模块进行抽象,如何抽象能检验一个程序员水平的高低。
今天先说一下我在学习过程中是怎么使用设计模式的思想进行重构项目的(自己领悟的,也不晓得这样使用对不对)。
首先在Dal层抽象一个工厂类
/// <summary> /// 抽象数据访问工厂类 /// </summary> /// <typeparam name="T"></typeparam> public abstract class AbstractDalFactiry<T> where T:class { /// <summary> /// 抽象工厂中添加数据的抽象方法 /// </summary> /// <param name="entity">要添加的实体类</param> /// <returns></returns> public abstract IAdd<T> Add(); /// <summary> /// 抽象工厂中修改数据的抽象方法 /// </summary> /// <param name="entity">要修改的实体类</param> /// <returns></returns> public abstract Ihandle<T> Update(); /// <summary> /// 抽象工厂中删除数据的抽象方法 /// </summary> /// <param name="entity">要删除的实体类</param> /// <returns></returns> public abstract Ihandle<T> Deleete(); /// <summary> /// 抽象工厂中要查询的实体类 /// </summary> /// <param name="entity">要查询的实体类</param> /// <returns></returns> public abstract SelectAccent<T> SelectAccent(); /// <summary> /// 抽象工厂中保存数据库的修改 /// </summary> /// <returns></returns> public abstract int SaveChange(); }
接着写一个抽象工厂实现类
public class DALFactiry<T> : AbstractDalFactiry<T> where T : class { DbContext DB = new DbContextFactory().CreateDbContext(); /// <summary> /// 添加,实例化添加类 /// </summary> /// <returns></returns> public override IAdd<T> Add() { return new Add<T>(DB); } /// <summary> /// 删除,实例化删除类 /// </summary> /// <returns></returns> public override Ihandle<T> Deleete() { return new Delete<T>(DB); } /// <summary> /// 查询,实例化查询类 /// </summary> /// <returns></returns> public override SelectAccent<T> SelectAccent() { return new SelectAccent<T>(DB); } /// <summary> /// 修改,实例化修改类 /// </summary> /// <returns></returns> public override Ihandle<T> Update() { return new Update<T>(DB); } /// <summary> /// 将更改保存到数据库 /// </summary> /// <returns></returns> public override int SaveChange() { return DB.SaveChanges(); } }
以查询为例
public class SelectAccent<T> where T:class { /// <summary> /// EF上下文对象 /// </summary> readonly DbContext Db = null; public SelectAccent(DbContext db) { Db = db; } #region 查询 /// <summary> /// 按照条件查询 /// </summary> /// <typeparam name="Tkey">键,查询时按什么排序</typeparam> /// <param name="whereLambda">查询条件</param> /// <param name="orderby">排序条件</param> /// Expression,list使用这个会直接将linq表达式转换成树结构查询。 /// <returns></returns> public IList<T> LoadEntites<Tkey>(Expression<Func<T, bool>> whereLambda, Expression<Func<T, Tkey>> orderby) { if (orderby==null) { return Db.Set<T>().Where(whereLambda).ToList(); } return Db.Set<T>().Where(whereLambda).OrderBy(orderby).ToList(); } /// <summary> /// 查询所有 /// </summary> /// <returns></returns> public IList<T> LoadEntitiesAll() { return Db.Set<T>().ToList(); } #endregion #region 分页查询 /// <summary> /// 分页查询 /// </summary> /// <typeparam name="key">排序键</typeparam> /// <param name="pageIndex">当前页码</param> /// <param name="pageSize">每页条数</param> /// <param name="paged">分页信息</param> /// <param name="whereLambda">条件</param> /// <param name="orderby">排序</param> /// <param name="desc"></param> /// <returns></returns> public List<T> LoadPageEntities<key>(int pageIndex, int pageSize, out PagedInfo paged, Expression<Func<T, bool>> whereLambda, Expression<Func<T, key>> orderby, bool desc = true) { IQueryable<T> tmp; if (desc) { //降序排列 tmp = Db.Set<T>().Where(whereLambda).OrderByDescending(orderby); } else { //升序排 tmp = Db.Set<T>().Where(whereLambda).OrderBy(orderby); } //将分页信息进行封装到实体类中 paged = new PagedInfo { TotalItems = tmp.Count(), CurrentPage = pageIndex, TotalPages = (tmp.Count() + pageIndex - 1) / pageSize }; //跳过当前页数减一页条数据 return tmp.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList(); } #endregion }
你会发现,其实很简单,无非就是定义了一个抽象类,一个实现工厂,之后工厂中封装了我的查询类中的泛型方法。在BLL层只需要调用这个工厂就可以了。这是我理解的泛型在抽象工厂模式中的使用
今天就先分享到这里了,持续学习,持续分享,欢迎各位大佬评论指导哦~