记一次.NET代码重构(上)
需求:是这样的,要开发一个短信发送的模板,不同客户可能会使用不同的模板,而不同的客户使用的变量参数也是不同的。
之前为了应急,线上已经完成了一个短信模板发送短信的功能,短信模板表也创建了,而且在表中已经新增了一条记录。我只需要做一个短信模板的增删改查界面就可以了,看上去我的任务挺简单的,老司机应该知道,接了个烂摊子。
下图所示是原来已经创建好了的表
SQL创建脚本如下:
在这之前是已经开发了一个发送短信的API接口供客户调用了的,也就是说调用方(客户),不会修改代码,只能我这边来修改。虽然极不情愿接做了一半的任务,但是没办法,不可能给你的开发任务都是从头开始的。
实体类代码如下:
DOT类:
这是之前的代码,业务实体类MessageModuleBusiness.cs代码如下:
public class MessageModuleBusiness : GenericRepository<Model.MessageModule> { private UnitOfWork.UnitOfWork unitOfWork = new UnitOfWork.UnitOfWork(); /// 获取模版内容 public string GetContent(MessageContext messageContext) { string messageContent = ""; string TypeCode = string.IsNullOrEmpty(messageContext.serviceCode) ? "001" : messageContext.serviceCode; try { var Module = unitOfWork.MessageModule.Get(c => c.Type == messageContext.channel && c.TypeNo == TypeCode).FirstOrDefault(); //Content的内容:【一应生活】您有一件单号为expressNumbers company, 已到communityName收发室,请打开一应生活APP“收发室”获取取件码进行取件。点击下载http://a.app.qq.com/o/simple.jsp?pkgname=com.ening.life if (!string.IsNullOrEmpty(Module.Content)) { var content = Module.Content; content = content.Replace("company", messageContext.company); content = content.Replace("expressNumbers", messageContext.expressNumbers); content = content.Replace("communityName", messageContext.communityName); content = content.Replace("Id", messageContext.Id); content = content.Replace("receiveTime", messageContext.receiveTime); content = content.Replace("fetchCode", messageContext.fetchCode); messageContent = content; } return messageContent; } catch (Exception ex) {} return ""; } #endregion }
MessageContext类,这个是客户端传输过来调用的一个实体对象。对象里面存在许多类似于短信的动态标签变量。
public class MessageContext{ /// 手机号码 public string phone { get; set; } /// 发送信息 public string message { get; set; } /// 签名 public string sign { get; set; } /// 渠道 public string channel { get; set; } /// 内容 public string content { get; set; } /// 取件码 public string fetchCode { get; set; } /// 快递公司 public string company { get; set; } /// 快递单号 public string expressNumbers { get; set; } /// 社区名称 public string communityName { get; set; } /// 到件时间 public string receiveTime { get; set; } /// 序号 public string Id { get; set; } /// 业务代码 public string serviceCode { get; set; } }
控制器方法externalMerchantSendMessage,这是供外部调用的
/// 外部商户发送信息 public ActionResult externalMerchantSendMessage(MessageContext param) { logger.Info("[externalMerchantSendMessage]param:" + param); bool isAuth = authModelBusiness.isAuth(param.channel, param.phone, param.sign); if (!isAuth) { return Json(new Result<string>() { resultCode = ((int)ResultCode.NoPermission).ToString(), resultMsg = "签名或无权限访问" }, JsonRequestBehavior.AllowGet); } var meaage = messageModuleBusiness.GetContent(param); if (string.IsNullOrEmpty(meaage)) { return Json(new Result<string>() { resultCode = ((int)ResultCode.failure).ToString(), resultMsg = "发送失败" }, JsonRequestBehavior.AllowGet); } SMSHelper helper = new SMSHelper(); helper.SendSMS(meaage, param.phone); return Json(new Result<string>() { resultCode = ((int)ResultCode.success).ToString(), resultMsg = "发送成功" }, JsonRequestBehavior.AllowGet); }
以上是我接收开发任务之前已经实现了的功能。看上去我的任务挺简单的,可是多年的开发经验告诉我,这里需要重构,如果我现在啥都不管,就只管做一个短信模板的增删改查界面的话,后面维护的人一定会抓狂。
看出什么问题没有?
这个接口方法externalMerchantSendMessage是给所有客户调用,而不同客户使用不同的短信模板,不同的模板,又存在不同的变量参数。而现在所有的变量参数都封装在了类MessageContext中,问题是我们无法一下子把所有的变量参数全部确定下来,并保持不变。
那么,也就是说一旦需要添加变量参数,类MessageContext中的代码就必须修改,而且GetContent方法中的代码是硬编的,一样需要跟着修改。这样就形成了一个循环,不断加变量参数,不断改代码,不断发布接口版本.......
时间充裕的情况下,我自然是一个有节操的程序猿,那么就开始重构吧。
在重构之前,在脑海浮现的并不是各种设计模式,而是面向对象设计的基本原则。各种设计模式就好比各种武学套路或者招式,习武之人应该像张无忌练习太极剑一样,先学会各种套路,然后忘记所有套路,从而融会贯通。
因为招式是死的,人是活得,有招就有破绽,根本没有必胜招式存在,就好像没有万能的设计模式一样,任何设计模式都存在缺点。
面向对象设计的核心思想就是封装变化,那么先找出变化点。从上面的分析中,我们已经发现了变化点,那就是短信模板中的变量参数,而这些变量参数都是客户调用方传过来的,不同客户传递的参数变量又可能是不一样的。
我们先来看一下,客户传递过来的是什么?我们看下客户调用代码,这里有Get和Post两种调用方式。
function sendMsg() { //var appParam ="phone=15914070649&sign=78a7ce797cf757916c2c7675b6865b54&channel=weijiakeji&content=&fetchCode=1 &company=%E9%A1%BA%E4%B8%B0%E5%BF%AB%E9%80%92&expressNumbers=123456&communityName=%E9%95%BF%E5%9F%8E%E4%B8%80%E8%8A%B1%E5%9B%AD&receiveTime=5&Id=1231"; //Get("/Message/externalMerchantSendMessage?" + appParam, {}); var data = { "phone": "15914070649", "sign": "78a7ce797cf757916c2c7675b6865b54", "channel": "weijiakeji", "fetchCode": 1, "company": "%E9%A1%BA%E4%B8%B0%E5%BF%AB%E9%80%92", "Id": "1231" }; Post('/Message/externalMerchantSendMessage', data); } //WebAPI Post方法 function Post(url, data) { $.ajax({ url: url, contentType: "application/json", type: "POST", dataType: "json", async: true, cache: false, data: JSON.stringify(data), success: function (response) { $('#response').text(JSON.stringify(response)); }, error: function (XMLHttpRequest, textStatus, errorThrown) { alert(textStatus); } }); }; //// WebApi Get方法 function Get(url, data) { $.ajax({ url: url, contentType: "application/json", type: "GET", dataType: "json", async: true, cache: false, //data: JSON.stringify(data), success: function (response) { $('#response').text(JSON.stringify(response)); }, error: function (XMLHttpRequest, textStatus, errorThrown) { alert(textStatus); } }); };
可见客户传递的是一个键值对集合,就是一个JSON格式的对象。根据前面的代码 bool isAuth = authModelBusiness.isAuth(param.channel, param.phone, param.sign);,可以分析出有三个参数是所有调用客户都必须传递过来的,那就是:channel,phone,sign,而其它的参数就是短信模板的变量参数和参数值。
那么方法externalMerchantSendMessage(MessageContext param)中的参数就是一个可变对象。在C#4.0种存在一个dynamic不正是用来描述可变对象吗?
那么第一步修改传入参数类型,之前是硬编码的强类型MessageContext,现在不依赖此类,而是动态解析,修改externalMerchantSendMessage方法代码如
下:
dynamic param = null; string json = Request.QueryString.ToString(); if (Request.QueryString.Count != 0) //ajax get请求 { //兼容旧的客户调用写法,暂时硬编了 if (json.Contains("param.")) { json = json.Replace("param.", ""); } json = "{" + json.Replace("=", ":'").Replace("&", "',") + "'}"; } else //ajax Post请求 { Request.InputStream.Position = 0; //切记这里必须设置流的起始位置为0,否则无法读取到数据 json = new StreamReader(Request.InputStream).ReadToEnd(); } var serializer = new JavaScriptSerializer(); serializer.RegisterConverters(new[] { new DynamicJsonConverter() }); param = serializer.Deserialize(json, typeof(object));
DynamicJsonConverter的作用是将JSON字符串转为Object对象,代码如下:
using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Dynamic; using System.Linq; using System.Text; using System.Web.Script.Serialization; public sealed class DynamicJsonConverter : JavaScriptConverter { public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer) { if (dictionary == null) throw new ArgumentNullException("dictionary"); return type == typeof(object) ? new DynamicJsonObject(dictionary) : null; } public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer) { throw new NotImplementedException(); } public override IEnumerable<Type> SupportedTypes { get { return new ReadOnlyCollection<Type>(new List<Type>(new[] { typeof(object) })); } } #region Nested type: DynamicJsonObject private sealed class DynamicJsonObject : DynamicObject { private readonly IDictionary<string, object> _dictionary; public DynamicJsonObject(IDictionary<string, object> dictionary) { if (dictionary == null) throw new ArgumentNullException("dictionary"); _dictionary = dictionary; } public override string ToString() { var sb = new StringBuilder("{"); ToString(sb); return sb.ToString(); } private void ToString(StringBuilder sb) { var firstInDictionary = true; foreach (var pair in _dictionary) { if (!firstInDictionary) sb.Append(","); firstInDictionary = false; var value = pair.Value; var name = pair.Key; if (value is string) { sb.AppendFormat("{0}:\"{1}\"", name, value); } else if (value is IDictionary<string, object>) { new DynamicJsonObject((IDictionary<string, object>)value).ToString(sb); } else if (value is ArrayList) { sb.Append(name + ":["); var firstInArray = true; foreach (var arrayValue in (ArrayList)value) { if (!firstInArray) sb.Append(","); firstInArray = false; if (arrayValue is IDictionary<string, object>) new DynamicJsonObject((IDictionary<string, object>)arrayValue).ToString(sb); else if (arrayValue is string) sb.AppendFormat("\"{0}\"", arrayValue); else sb.AppendFormat("{0}", arrayValue); } sb.Append("]"); } else { sb.AppendFormat("{0}:{1}", name, value); } } sb.Append("}"); }
以上就是记一次.NET代码重构(上)的内容,更多相关内容请关注PHP中文网(www.php.cn)!

Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

Video Face Swap
Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Topik panas





Bagaimana untuk menyelesaikan masalah redundansi kod dalam pembangunan C++ Redundansi kod bermakna apabila menulis program, terdapat kod yang serupa atau berulang di beberapa tempat. Masalah ini bukan sahaja menjadikan kod sukar untuk dikekalkan dan dibaca, tetapi juga meningkatkan saiz dan kerumitan kod. Bagi pembangun C++, adalah amat penting untuk menyelesaikan masalah redundansi kod, kerana C++ ialah bahasa pengaturcaraan yang berkuasa, tetapi ia juga boleh membawa kepada pertindihan kod dengan mudah. Punca masalah lebihan kod terletak pada reka bentuk dan tabiat pengekodan yang tidak munasabah. Untuk menyelesaikan masalah ini, anda boleh bermula dari aspek berikut: Gunakan fungsi dan kelas: C

Apabila masa berlalu dan keperluan berubah, kod projek dengan mudah boleh menjadi usang dan sukar untuk diselenggara dan dilanjutkan. Dalam pembangunan PHP, pemfaktoran semula dianggap sebagai salah satu tugas yang diperlukan untuk meningkatkan kualiti kod dan kecekapan pembangunan. Dalam proses ini, menggunakan alat Rektor boleh memudahkan kerja pembinaan semula dan pengoptimuman kod. Rector ialah alat pembinaan semula kod PHP sumber terbuka yang boleh membantu pembangun PHP mengautomasikan pembinaan semula dan pengoptimuman kod, membolehkan pembangun menumpukan lebih pada pembangunan perniagaan dan pelaksanaan fungsi. lulus

Sama ada anda seorang pemula atau profesional yang berpengalaman, menguasai C# akan membuka jalan untuk kerjaya anda.

Perkembangan teknologi kecerdasan buatan (AI) sedang giat dijalankan hari ini, dan ia telah menunjukkan potensi dan pengaruh yang besar dalam pelbagai bidang. Hari ini Dayao akan berkongsi dengan anda 4 rangka kerja projek berkaitan LLM model AI sumber terbuka .NET, dengan harapan dapat memberi anda sedikit rujukan. https://github.com/YSGStudyHards/DotNetGuide/blob/main/docs/DotNet/DotNetProjectPicks.mdSemanticKernelSemanticKernel ialah kit pembangunan perisian sumber terbuka (SDK) yang direka untuk menyepadukan model bahasa besar (LLM) seperti OpenAI, Azure

Pemfaktoran semula adalah proses yang sangat penting semasa menulis kod PHP. Apabila aplikasi berkembang, pangkalan kod menjadi lebih besar dan lebih sukar untuk dibaca dan diselenggara. Pemfaktoran semula adalah untuk menyelesaikan masalah ini dan menjadikan kod lebih modular dan lebih teratur dan boleh diperluaskan. Apabila kita memfaktorkan semula kod, kita perlu mengambil kira aspek berikut: Gaya kod Gaya kod ialah perkara yang sangat penting. Memastikan gaya pengekodan anda konsisten akan menjadikan kod anda lebih mudah dibaca dan diselenggara. Sila ikut piawaian pengekodan PHP dan konsisten. Cuba gunakan alat semakan gaya kod seperti PHP

Pembangunan Java: Pemfaktoran Semula Kod dan Penilaian Kualiti Pengenalan: Dalam proses pembangunan perisian, pemfaktoran semula kod adalah salah satu cara penting untuk meningkatkan kualiti dan kebolehselenggaraan kod. Dengan memfaktorkan semula kod, anda boleh menjadikan kod lebih elegan, ringkas, mudah difahami dan diubah suai. Walau bagaimanapun, pemfaktoran semula bukan sekadar mengubah suai kod, tetapi proses yang memerlukan pemikiran yang rasional dan sistematik. Artikel ini akan memperkenalkan cara melakukan pemfaktoran semula kod dan menggambarkannya dengan contoh kod tertentu. Kami juga akan membincangkan cara menilai kualiti kod dan mengapa penilaian itu penting. Kod berat

Inferens jenis nilai pulangan bahasa Go secara automatik menyimpulkan jenis nilai pulangan fungsi, memudahkan kod dan meningkatkan kebolehbacaan. Jenis nilai pulangan boleh diabaikan dan pengkompil secara automatik akan membuat kesimpulan jenis berdasarkan nilai pulangan sebenar dalam badan fungsi. Boleh digunakan untuk memfaktorkan semula kod sedia ada untuk menghapuskan pengisytiharan jenis eksplisit Contohnya, fungsi calculateTotal yang mengira jumlah tatasusunan integer boleh difaktorkan semula menjadi: funccalculateTotal(items[]int){}.

Cara menggunakan bahasa Go untuk pengenalan amalan pemfaktoran semula kod: Dalam proses pembangunan perisian, kami sering menghadapi cabaran pemfaktoran semula kod. Pemfaktoran semula kod merujuk kepada pengoptimuman dan penstrukturan semula kod sedia ada untuk meningkatkan kualiti dan kebolehselenggaraan kod. Artikel ini akan memperkenalkan cara menggunakan bahasa Go untuk amalan pemfaktoran semula kod dan disertakan dengan contoh kod yang sepadan. 1. Prinsip pemfaktoran semula kod Sebelum pemfaktoran semula kod, kita perlu menjelaskan beberapa prinsip untuk memastikan kelancaran kemajuan pemfaktoran semula. Berikut adalah beberapa prinsip pemfaktoran semula kod yang penting: Mengekalkan ketekalan fungsi kod: Selepas pemfaktoran semula
