我个人是做一名.net开发工程师,欢迎跟我讨论关于技术问题
下面跟大家说一下我的见解,有相关领域的问题可以一起探讨。ps(不喜勿喷)各种开发都是一家 java/.net/……,只要思想在,万事不用愁!
为什么要用程序设计?程序是面向对象思想,不要面向过程。面向对象的意思可以得到易扩展易维护易开发的过程。
通常设计应该由什么人来设计?通常会由架构师,项目组长负责人等。
设计应该考虑哪些因素?设计就是考虑不稳定因素换做稳定因素、大量减少工作量、安全因素、易扩展易维护易开发。
个人喜欢撸码,我先给大家介绍一个简单的例子大家从例子中得到解答
我首先拿到需求,需求是这样说的 {A客户要求做一个财务服务,用途给下面人拨款业务,用A银行,跟现有程序关联}
现在拿到需求有时领导直接问你多长时间能搞出来,说实话写某个功能或者程序有不稳定因素,很多小单位没有那种意识,只有出现必然是一种损失,为了把工程成本,质量降到最低,必须要纠正。(个人现在在学习一些pmp相关管理,有管理方面也可以一起探讨)
拿到需求别着急,先跟领导说给我一天时间我想解决方案。给出的这句话意思就是看做的过程中有哪些因素存在,提供出多种思路解决方案,给领导汇报这些问题,让领导知道这个项目是可以把控的。
就拿到的需求说事,需要考虑几点,学会分析
1、需要做拨款业务,是否需要拨款回调查询
2、除了拨款业务是否还需要收款业务
3、是否需要流水账查询
4、信息校验
5、用银联方式是否接受有利息
6、用银行接口客户改变银行
7、客户增加不同银行进入
........很多具体就不一一了解。
得到这些需求分析应该总结出来一份报告、因为项目需要给领导看你的分析报告,领导一看,确实是这么回事,然后就会需求这边继续挖深。因为每个项目不可能赔钱去做,所以必要的成本需要把控。不能让领导觉得你给我干活我怎么老赔钱啊!!!
得到需求呢,咱也不能光闲着,等着需求到了在开始干活、咱可以先写一个框架,框架的目的就是你分析出来的结论进行解决、银行增多或减少。客户增加或减少怎么处理比较好。不可能因为一个客户的介入影响到我的代码,不能加入银行影响到我的其他代码。在这个框架上写代码还要很轻松的那种,写几个方法就能搞定。
设计的时候要想的全面,全面的意思就是你成功上线之后根据客户量同时使用会不会照成影响,程序安全问题,其次是性能问题。给搬砖工写好注释规范体系结构。
现在安全问题以后再提,先说多个用户同时使用就是多线程问题、性能问题、搬砖工的问题(我也是一个搬砖工没有歧视,自己能力不足时就要提升,不然永远也是板砖,我醒悟了好多年)
我先用.net代码翻译成多数人可以听懂的,再有不懂的私下练习
拿到刚刚得出的结论报告,得到的不稳定因素,稳定因素。慢慢来分析,稳定因素是什么,(银行),不稳定因素是什么(客户)。银行是稳定的那就先写银行
银行的共同点提供了查询、付款、收款等业务不变
各个银行都一样先写一个接口把
1 public interface Bank 2 { 3 /// <summary> 4 /// 银行查询 5 /// </summary> 6 void Query(); 7 /// <summary> 8 /// 银行波付款 9 /// </summary> 10 void Payment(); 11 /// <summary> 12 /// 银行收款 13 /// </summary> 14 void Gathering(); 15 }
接下来就是各个实现的类
建设银行业务,去实现接口
1 /// <summary> 2 /// 建设银行业务 3 /// </summary> 4 public class Construction:Bank.Interface.Bank 5 { 6 /// <summary> 7 /// 建设银行 8 /// </summary> 9 public Construction() { 10 Console.WriteLine("这里时建设银行,被构造"); 11 12 } 13 /// <summary> 14 /// 建设银行查询业务操作 15 /// </summary> 16 public void Query() { 17 Console.WriteLine("建设银行查询业务"); 18 } 19 /// <summary> 20 /// 建设银行波付款业务 21 /// </summary> 22 public void Payment() { 23 Console.WriteLine("建设银行波付款业务"); 24 25 } 26 /// <summary> 27 /// 建设银行收款业务 28 /// </summary> 29 public void Gathering() { 30 Console.WriteLine("建设银行收款业务"); 31 } 32 33 34 }
招商银行业务,去实现接口
1 /// <summary> 2 /// 招商银行业务 3 /// </summary> 4 public class Merchants : Bank.Interface.Bank 5 { 6 /// <summary> 7 /// 招商银行 8 /// </summary> 9 public Merchants() { 10 Console.WriteLine("这里时招商银行业务,被构造"); 11 } 12 /// <summary> 13 /// 招商银行查询业务操作 14 /// </summary> 15 public void Query() 16 { 17 Console.WriteLine("招商银行查询业务"); 18 } 19 /// <summary> 20 /// 招商银行波付款业务 21 /// </summary> 22 public void Payment() 23 { 24 Console.WriteLine("招商银行波付款业务"); 25 26 } 27 /// <summary> 28 /// 招商银行收款业务 29 /// </summary> 30 public void Gathering() 31 { 32 Console.WriteLine("招商银行收款业务"); 33 } 34 }
。。。。等我就不一个个的介绍
接下来就是整个核心的关键,写了一个工厂类库,主要原理就是你根据我的规范去开发,我就保证没问题,优化性能静态数据,异步处理工作有注释
1 /// <summary> 2 /// UnityConfig类库 3 /// </summary> 4 public class UnityConfig 5 { 6 /// <summary> 7 /// 读配置文件 8 /// </summary> 9 private static string ConfigContainer = ConfigurationManager.AppSettings["ConfigContainer"]; 10 /// <summary> 11 /// 配置文件集合 12 /// </summary> 13 private static List<ConfigType> listconfig = new List<ConfigType>(); 14 /// <summary> 15 /// 线程锁 16 /// </summary> 17 private readonly static object oblook = new object(); 18 /// <summary> 19 /// 初始化添加配置项,加载一次跳过 20 /// </summary> 21 public UnityConfig() 22 { 23 if (!string.IsNullOrEmpty(ConfigContainer)) 24 { 25 if(listconfig.Count==0) 26 { 27 try 28 { 29 string[] configs = ConfigContainer.Split(';'); 30 for (int i = 0; i < configs.Count()-1; i++) 31 { 32 ConfigType type = new ConfigType(); 33 type.USER = configs[i].Split(',')[0]; 34 type.TYPE = configs[i].Split(',')[1]; 35 type.BANK = configs[i].Split(',')[2]; 36 listconfig.Add(type); 37 } 38 } 39 catch (Exception) 40 { 41 Console.WriteLine("配置config文件出错参照注释说明配置"); 42 throw; 43 } 44 45 } 46 } 47 48 } 49 /// <summary> 50 /// 映射 51 /// </summary> 52 private static ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap(); 53 /// <summary> 54 /// 银行功能扩展 55 /// </summary> 56 /// <param name="typeid"></param> 57 /// <param name="type"></param> 58 59 public static void Show(string typeid, Methodtype type) 60 { 61 lock (oblook) 62 { 63 IUnityContainer container = new UnityContainer(); 64 65 #region 配置文件方案 66 if (string.IsNullOrEmpty(fileMap.ExeConfigFilename)) 67 { 68 fileMap.ExeConfigFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory + "CfgFiles\Unity.Config.xml");//找配置文件的路径 69 } 70 Configuration configuration = UnityConfig.CacheGet("configuration", () => ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None)); 71 UnityConfigurationSection section = UnityConfig.CacheGet("section", () => (UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName)); 72 #endregion 73 74 //利用缓存构造 75 ConfigType configType = UnityConfig.CacheGet("QueryType"+typeid,()=> listconfig.Where(mr => mr.TYPE == typeid).First()); 76 77 section.Configure(container, configType.BANK);//注册 78 Bank.Interface.Bank bank = container.Resolve<Bank.Interface.Bank>(); 79 DelegateBank delegateBank = null; 80 switch (type) 81 { 82 case Methodtype.Query: 83 delegateBank= new DelegateBank(bank.Query); 84 break; 85 case Methodtype.Payment: 86 delegateBank = new DelegateBank(bank.Payment); 87 break; 88 case Methodtype.Gathering: 89 delegateBank = new DelegateBank(bank.Gathering); 90 break; 91 default: 92 Console.WriteLine("参数类型错误"); 93 break; 94 } 95 96 SayHiPerfact(delegateBank); 97 } 98 99 100 } 101 public static void SayHiPerfact(DelegateBank method) 102 { 103 try 104 { 105 method.Invoke(); 106 } 107 catch (Exception) 108 { 109 Console.WriteLine("写日志 出错了 DelegateBank不知道该方法"); 110 throw; 111 } 112 113 } 114 public delegate void DelegateBank (); 115 /// <summary> 116 /// 方法枚举 117 /// </summary> 118 public enum Methodtype 119 { 120 /// <summary> 121 /// 银行查询业务 122 /// </summary> 123 Query = 1, 124 /// <summary> 125 /// 银行波付款业务 126 /// </summary> 127 Payment = 2, 128 /// <summary> 129 /// 银行收款业务 130 /// </summary> 131 Gathering = 3 132 } 133 134 /// <summary> 135 /// 缓存机制 136 /// </summary> 137 private static Dictionary<string, object> _CustomCacheDictionary = new Dictionary<string, object>(); 138 /// <summary> 139 /// 缓存添加 140 /// </summary> 141 private static void Add(string key, object value) 142 { 143 _CustomCacheDictionary[key] = value; 144 } 145 /// <summary> 146 /// 缓存返回集合 147 /// </summary> 148 private static T Query<T>(string key) 149 { 150 return (T)_CustomCacheDictionary[key]; 151 } 152 /// <summary> 153 /// 缓存查询 154 /// </summary> 155 private static bool Exist(string key) 156 { 157 return _CustomCacheDictionary.ContainsKey(key); 158 } 159 /// <summary> 160 /// 缓存构造 161 /// </summary> 162 /// <typeparam name="T"></typeparam> 163 /// <param name="key"></param> 164 /// <param name="func"></param> 165 /// <returns></returns> 166 public static T CacheGet<T>(string key, Func<T> func) 167 { 168 T result = default(T); 169 if (UnityConfig.Exist(key)) 170 { 171 result = UnityConfig.Query<T>(key); 172 } 173 else 174 { 175 result = func.Invoke(); 176 UnityConfig.Add(key, result); 177 } 178 return result; 179 } 180 public class ConfigType { 181 public string USER { get; set; } 182 public string TYPE { get; set; } 183 public string BANK { get; set; } 184 185 } 186 187 }
我用IOC设计模式去设计,DIP容器放银行不变的参数配置文件,客户是改变的有两种方案,一种是写入config配置文件中读取,另一种直接写入数据库中,加一个管理授权页面
我先把配置文件整体代码贴出来
<add key="ConfigContainer" value="ChinaSouthernAirlines,1,Construction;ChinaNorthing,2,Merchants;ChinaWesting,3,Minsheng;ChinaEasternAirlines,4,Construction;"/>
这是配置客户
配置银行我选择XML格式节点格式
1 <configuration> 2 <configSections> 3 <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/> 4 </configSections> 5 <unity> 6 <containers> 7 8 <!--建设银行--> 9 <container name="Construction"> 10 <!--建设银行--> 11 <register type="Bank.Interface.Bank,Bank.Interface" mapTo="FinanceBusiness.Construction, FinanceBusiness" /> 12 13 </container> 14 15 <!--招商银行--> 16 <container name="Merchants"> 17 <!--招商银行--> 18 <register type="Bank.Interface.Bank,Bank.Interface" mapTo="FinanceBusiness.Merchants, FinanceBusiness" /> 19 </container> 20 21 <!--民生银行--> 22 <container name="Minsheng"> 23 <!--民生银行--> 24 <register type="Bank.Interface.Bank,Bank.Interface" mapTo="FinanceBusiness.Minsheng, FinanceBusiness" /> 25 </container> 26 27 </containers> 28 </unity> 29 </configuration>
我一般写一点就考试调试
我调试的方案就是上线程,线程同时跑看会不会出现问题,写代码最重要的核心就是写出你能预想到的结果,去掉不稳定的结果。
1 static void Main(string[] args) 2 { 3 //财务银行接口准备参数工作 4 //IOC配置工厂 5 Console.WriteLine("****************这里是财务银行接口*******************"); 6 7 8 { 9 //下面用第三方Unity使用 在nuget里面找 10 new UnityConfig(); 11 Action action = new Action(taskrun); 12 action.BeginInvoke(null,null); 13 14 15 UnityConfig.Show("2",UnityConfig.Methodtype.Query); 16 UnityConfig.Show("3",UnityConfig.Methodtype.Payment); 17 //UnityConfig.Show("4"); 18 19 } 20 Console.Read(); 21 22 } 23 24 public static void taskrun() { 25 26 for (int i = 1; i < 5; i++) 27 { 28 UnityConfig.Show(i.ToString(),UnityConfig.Methodtype.Gathering); 29 for (int j = 1; j < 5; j++) 30 { 31 UnityConfig.Show(j.ToString(), UnityConfig.Methodtype.Payment); 32 } 33 } 34 }
好处在哪里,好处在于银行增加你按我的规则来,生成直接发包,有客户进入直接配置,有银行参数变动,改变需要改变的参数发包。解决了代码的复用。节省人力的开发
有技术讨论研究的可以发至
邮箱: ms.gaoxiong@outlook.com
QQ:1367538691