大龄程序员谈架构经验内行看门道
前言
孔乙己显出极高兴的样子,将两个指头的长指甲敲着柜台,点头说:"对呀,对呀!......回字有四样写法,你知道么?"
大家好,我是44岁的大龄程序员码农阿峰。阿峰从事编程二十年了,虽然没有成为架构师,却也用过很多种架构。我觉得一招鲜走遍天,架构师常用的那几招我还是会的,听我来说道说道。我以为至少有这几招: 模板方法设计模式 反射 不重复造轮子,集众家所长 架构经验总结
1).模板方法设计模式的运用
在一个方法中定义了一个算法的骨架或者步骤,而将一些步骤延迟到子类中去实现。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某一些步骤。 #父类: namespace Repository { /// /// 数据库存储泛型基类 /// /// public class BaseRepository : SimpleClient where T : class, new() { public ITenant itenant = null;//多租户事务 public BaseRepository(ISqlSugarClient context = null) : base(context) { //通过特性拿到ConfigId var configId = typeof(T).GetCustomAttribute()?.configId; if (configId != null) { Context = DbScoped.SugarScope.GetConnectionScope(configId);//根据类传入的ConfigId自动选择 } else { Context = context ?? DbScoped.SugarScope.GetConnectionScope(0);//没有默认db0 } itenant = DbScoped.SugarScope;//设置租户接口 } #region add /// /// 插入实体 /// /// /// public int Add(T t) { return Context.Insertable(t).IgnoreColumns(true).ExecuteCommand(); } public int Insert(List t) { return Context.Insertable(t).ExecuteCommand(); } public int Insert(T parm, Expression> iClumns = null, bool ignoreNull = true) { return Context.Insertable(parm).InsertColumns(iClumns).IgnoreColumns(ignoreNullColumn: ignoreNull).ExecuteCommand(); } public IInsertable Insertable(T t) { return Context.Insertable(t); } #endregion add #region update public IUpdateable Updateable(T entity) { return Context.Updateable(entity); } public int Update(T entity, bool ignoreNullColumns = false) { return Context.Updateable(entity).IgnoreColumns(ignoreNullColumns).ExecuteCommand(); } public int Update(T entity, Expression> expression, bool ignoreAllNull = false) { return Context.Updateable(entity).UpdateColumns(expression).IgnoreColumns(ignoreAllNull).ExecuteCommand(); } /// /// 根据实体类更新指定列 eg:Update(dept, it => new { it.Status }, f => depts.Contains(f.DeptId));只更新Status列,条件是包含 /// /// /// /// /// public int Update(T entity, Expression> expression, Expression> where) { return Context.Updateable(entity).UpdateColumns(expression).Where(where).ExecuteCommand(); } public int Update(SqlSugarClient client, T entity, Expression> expression, Expression> where) { return client.Updateable(entity).UpdateColumns(expression).Where(where).ExecuteCommand(); } /// /// /// /// /// /// 默认为true /// public int Update(T entity, List list = null, bool isNull = true) { if (list == null) { list = new List() { "Create_By", "Create_time" }; } return Context.Updateable(entity).IgnoreColumns(isNull).IgnoreColumns(list.ToArray()).ExecuteCommand(); } /// /// 更新指定列 eg:Update(w => w.NoticeId == model.NoticeId, it => new SysNotice(){ Update_time = DateTime.Now, Title = "通知标题" }); /// /// /// /// public int Update(Expression> where, Expression> columns) { return Context.Updateable().SetColumns(columns).Where(where).RemoveDataCache().ExecuteCommand(); } #endregion update public DbResult UseTran(Action action) { try { var result = Context.Ado.UseTran(() => action()); return result; } catch (Exception ex) { Context.Ado.RollbackTran(); Console.WriteLine(ex.Message); throw; } } public IStorageable Storageable(T t) { return Context.Storageable(t); } public IStorageable Storageable(List t) { return Context.Storageable(t); } /// /// /// /// /// 增删改查方法 /// public DbResult UseTran(SqlSugarClient client, Action action) { try { var result = client.AsTenant().UseTran(() => action()); return result; } catch (Exception ex) { client.AsTenant().RollbackTran(); Console.WriteLine(ex.Message); throw; } } public bool UseTran2(Action action) { var result = Context.Ado.UseTran(() => action()); return result.IsSuccess; } #region delete public IDeleteable Deleteable() { return Context.Deleteable(); } /// /// 批量删除 /// /// /// public int Delete(object[] obj) { return Context.Deleteable().In(obj).ExecuteCommand(); } public int Delete(object id) { return Context.Deleteable(id).ExecuteCommand(); } public int DeleteTable() { return Context.Deleteable().ExecuteCommand(); } public bool Truncate() { return Context.DbMaintenance.TruncateTable(); } #endregion delete #region query public bool Any(Expression> expression) { return Context.Queryable().Where(expression).Any(); } public ISugarQueryable Queryable() { return Context.Queryable(); } public (List, int) QueryableToPage(Expression> expression, int pageIndex = 0, int pageSize = 10) { int totalNumber = 0; var list = Context.Queryable().Where(expression).ToPageList(pageIndex, pageSize, ref totalNumber); return (list, totalNumber); } public (List, int) QueryableToPage(Expression> expression, string order, int pageIndex = 0, int pageSize = 10) { int totalNumber = 0; var list = Context.Queryable().Where(expression).OrderBy(order).ToPageList(pageIndex, pageSize, ref totalNumber); return (list, totalNumber); } public (List, int) QueryableToPage(Expression> expression, Expression> orderFiled, string orderBy, int pageIndex = 0, int pageSize = 10) { int totalNumber = 0; if (orderBy.Equals("DESC", StringComparison.OrdinalIgnoreCase)) { var list = Context.Queryable().Where(expression).OrderBy(orderFiled, OrderByType.Desc).ToPageList(pageIndex, pageSize, ref totalNumber); return (list, totalNumber); } else { var list = Context.Queryable().Where(expression).OrderBy(orderFiled, OrderByType.Asc).ToPageList(pageIndex, pageSize, ref totalNumber); return (list, totalNumber); } } public List SqlQueryToList(string sql, object obj = null) { return Context.Ado.SqlQuery(sql, obj); } /// /// 根据主值查询单条数据 /// /// 主键值 /// 泛型实体 public T GetId(object pkValue) { return Context.Queryable().InSingle(pkValue); } /// /// 根据条件查询分页数据 /// /// /// /// public PagedInfo GetPages(Expression> where, PagerInfo parm) { var source = Context.Queryable().Where(where); return source.ToPage(parm); } public PagedInfo GetPages(Expression> where, PagerInfo parm, Expression> order, OrderByType orderEnum = OrderByType.Asc) { var source = Context.Queryable().Where(where).OrderByIF(orderEnum == OrderByType.Asc, order, OrderByType.Asc).OrderByIF(orderEnum == OrderByType.Desc, order, OrderByType.Desc); return source.ToPage(parm); } public PagedInfo GetPages(Expression> where, PagerInfo parm, Expression> order, string orderByType) { return GetPages(where, parm, order, orderByType == "desc" ? OrderByType.Desc : OrderByType.Asc); } /// /// 查询所有数据(无分页,请慎用) /// /// public List GetAll(bool useCache = false, int cacheSecond = 3600) { return Context.Queryable().WithCacheIF(useCache, cacheSecond).ToList(); } #endregion query /// /// 此方法不带output返回值 /// var list = new List(); /// list.Add(new SugarParameter(ParaName, ParaValue)); input /// /// /// /// public DataTable UseStoredProcedureToDataTable(string procedureName, List parameters) { return Context.Ado.UseStoredProcedure().GetDataTable(procedureName, parameters); } /// /// 带output返回值 /// var list = new List(); /// list.Add(new SugarParameter(ParaName, ParaValue, true)); output /// list.Add(new SugarParameter(ParaName, ParaValue)); input /// /// /// /// public (DataTable, List) UseStoredProcedureToTuple(string procedureName, List parameters) { var result = (Context.Ado.UseStoredProcedure().GetDataTable(procedureName, parameters), parameters); return result; } } /// /// 分页查询扩展 /// public static class QueryableExtension { /// /// 读取列表 /// /// /// 查询表单式 /// 分页参数 /// public static PagedInfo ToPage(this ISugarQueryable source, PagerInfo parm) { var page = new PagedInfo(); var total = 0; page.PageSize = parm.PageSize; page.PageIndex = parm.PageNum; page.Result = source.OrderByIF(!string.IsNullOrEmpty(parm.Sort), #34;{parm.Sort} {(parm.SortType.Contains("desc") ? "desc" : "asc")}") .ToPageList(parm.PageNum, parm.PageSize, ref total); page.TotalNum = total; return page; } } } #子类: [AppService(ServiceLifetime = LifeTime.Transient)] public class GenDemoRepository : BaseRepository { #region 业务逻辑代码 #endregion }
现在大家都学精了,都使用泛型基类来简化重复的代码,标准的架构还是按经典的三层架构标准来搭建。这个是基本功,不用说太细。
2).反射
反射:是.Net Framework和.Net Core提供的一个帮助类库,可以访问dll的metadata,并且使用它。
反射反射,程序员的快乐 /// /// 注册引用程序域中所有有AppService标记的类的服务 /// /// public static void AddAppService(this IServiceCollection services) { //var assemblies = AppDomain.CurrentDomain.GetAssemblies(); string []cls = new string[] { "Topaut.Repository", "Topaut.Service", "Topaut.Tasks" }; foreach (var item in cls) { Assembly assembly = Assembly.Load(item); Register(services, assembly); } } private static void Register(IServiceCollection services, Assembly assembly) { foreach (var type in assembly.GetTypes()) { var serviceAttribute = type.GetCustomAttribute(); if (serviceAttribute != null) { var serviceType = serviceAttribute.ServiceType; //情况1 适用于依赖抽象编程,注意这里只获取第一个 if (serviceType == null && serviceAttribute.InterfaceServiceType) { serviceType = type.GetInterfaces().FirstOrDefault(); } //情况2 不常见特殊情况下才会指定ServiceType,写起来麻烦 if (serviceType == null) { serviceType = type; } switch (serviceAttribute.ServiceLifetime) { case LifeTime.Singleton: services.AddSingleton(serviceType, type); break; case LifeTime.Scoped: services.AddScoped(serviceType, type); break; case LifeTime.Transient: services.AddTransient(serviceType, type); break; default: services.AddTransient(serviceType, type); break; } //Console.WriteLine(#34;注册:{serviceType}"); } else { //Console.WriteLine(#34;注册:{serviceType}"); } } } }
官方各种Service注入IOC容器都是手写,框架作者利用反射实现了减少大量繁琐的固定写法,对于普通项目而言,反射的性能损耗微不足道的。
3).不重复造轮子集众家所长
有时程序员喜欢浪费生命去重复造轮子,如果是为了学习一次怎么造轮子是值得肯定的。否则就是吃饱了没事干闲的。现在是最好的时代(好多开源组件可用),也是最坏的时代(行业太卷)。框架作者使用了糖果大数据的开源组件SqlSugar来实现多数据库类型的支持,还有多租户,读写分离,分表分库这些数据库层面的数据存储方案。实现前后端分离参考了一些其他的优秀Vue实现的Admin框架。
在线体验官方文档:http://www.izhaorui.cn/doc vue3.x版本体验:http://www.izhaorui.cn/vue3 vue2.x版本体验:http://www.izhaorui.cn/admin 账号密码:admin/123456
https://gitee.com/izory/ZrAdminNetCore/