Erinnern Sie sich an ein .NET-Code-Refactoring (Teil 1)

黄舟
Freigeben: 2017-02-06 14:37:00
Original
1195 Leute haben es durchsucht

Voraussetzung: Um eine Vorlage zum Versenden von Textnachrichten zu entwickeln, können verschiedene Kunden unterschiedliche Vorlagen verwenden, und auch die von verschiedenen Kunden verwendeten variablen Parameter sind unterschiedlich.


Für den Notfall wurde eine SMS-Vorlagenfunktion zum Versenden von Textnachrichten online erstellt und ein neuer Datensatz hinzugefügt zum Tisch. Ich muss nur eine Schnittstelle zum Hinzufügen, Löschen, Ändern und Überprüfen von Textnachrichtenvorlagen erstellen. Ein erfahrener Fahrer sollte wissen, dass ich in ein Chaos geraten bin.


Das Bild unten zeigt die ursprünglich erstellte Tabelle

Erinnern Sie sich an ein .NET-Code-Refactoring (Teil 1)

Das SQL-Erstellungsskript lautet wie folgt:

Erinnern Sie sich an ein .NET-Code-Refactoring (Teil 1)

Zuvor wurde eine API-Schnittstelle zum Senden von Textnachrichten entwickelt, die der Anrufer (Kunde) nicht ändern kann, sondern nur ich. Obwohl ich äußerst ungern halbfertige Aufgaben übernehme, bleibt mir nichts anderes übrig, als alle Entwicklungsaufgaben von vorne zu beginnen.


Der Entitätsklassencode lautet wie folgt:

Erinnern Sie sich an ein .NET-Code-Refactoring (Teil 1)

DOT-Klasse:

Erinnern Sie sich an ein .NET-Code-Refactoring (Teil 1)

Dies ist der vorherige Code. Der Code der Geschäftsentitätsklasse MessageModuleBusiness.cs lautet wie folgt:

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
}
Nach dem Login kopieren

MessageContext-Klasse, dies ist ein vom Client übertragenes und aufgerufenes Entitätsobjekt. Es gibt viele dynamische Tag-Variablen, die Textnachrichten im Objekt ähneln.

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; }
    }
Nach dem Login kopieren

Controller-Methode externalMerchantSendMessage, die für externe Aufrufe vorgesehen ist

    /// 外部商户发送信息
        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);
        }
Nach dem Login kopieren

Die oben genannten Funktionen sind die Funktionen, die ich implementiert habe, bevor ich die Entwicklungsaufgabe erhalten habe. Es scheint, dass meine Aufgabe recht einfach ist, aber viele Jahre Erfahrung in der Entwicklung sagen mir, dass dies überarbeitet werden muss Die Wartungsleute werden in Zukunft definitiv verrückt werden.


Sehen Sie ein Problem?


Diese Schnittstellenmethode externalMerchantSendMessage wird für alle Kunden aufgerufen, und verschiedene Kunden verwenden unterschiedliche SMS-Vorlagen, und unterschiedliche Vorlagen haben unterschiedliche variable Parameter. Jetzt sind alle variablen Parameter in der MessageContext-Klasse gekapselt. Das Problem besteht darin, dass wir nicht alle variablen Parameter auf einmal ermitteln und unverändert lassen können.


Das heißt, sobald variable Parameter hinzugefügt werden müssen, muss der Code in der MessageContext-Klasse geändert werden, und der Code in der GetContent-Methode ist hart. codiert und muss entsprechend angepasst werden. Dies bildet einen Zyklus, der ständig variable Parameter hinzufügt, den Code ständig ändert und ständig Schnittstellenversionen veröffentlicht ...


Wenn ich genug Zeit habe, werde ich natürlich Wenn Sie ein sind disziplinierter Programmierer, dann beginnen Sie mit dem Refactoring.


Vor dem Refactoring fallen mir nicht verschiedene Designmuster ein, sondern die Grundprinzipien des objektorientierten Designs. Verschiedene Designmuster sind wie verschiedene Kampfsportroutinen oder -bewegungen. Kampfsportler sollten wie Zhang Wuji beim Tai Chi-Schwert zuerst verschiedene Routinen lernen und dann alle Routinen vergessen, um sie zu meistern.


Denn Bewegungen sind tot, Menschen leben und jede Bewegung hat ihre Fehler. Es gibt überhaupt keine sichere Entscheidung, genauso wie es kein universelles Designmuster gibt. jedes Design Alle Modelle weisen Mängel auf.


Die Kernidee des objektorientierten Designs besteht darin, Änderungen zu kapseln. Finden Sie daher zunächst die Änderungspunkte. Aus der obigen Analyse haben wir den Änderungspunkt entdeckt, bei dem es sich um die variablen Parameter in der SMS-Vorlage handelt. Diese variablen Parameter werden vom Kundenanrufer übergeben, und die von verschiedenen Kunden übergebenen Parametervariablen können unterschiedlich sein.


Werfen wir zunächst einen Blick darauf, was vom Kunden weitergegeben wird? Werfen wir einen Blick auf den Kundenaufrufcode. Es gibt zwei Aufrufmethoden: Get und 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(&#39;/Message/externalMerchantSendMessage&#39;, 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) {
                    $(&#39;#response&#39;).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) {
                    $(&#39;#response&#39;).text(JSON.stringify(response));
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    alert(textStatus);
                }
            });
        };
Nach dem Login kopieren

Es ist ersichtlich, dass der Kunde eine Sammlung von Schlüssel-Wert-Paaren übergibt, bei denen es sich um ein Objekt im JSON-Format handelt. Gemäß dem vorherigen Code bool isAuth = authModelBusiness.isAuth(param.channel, param.phone, param.sign); kann analysiert werden, dass alle anrufenden Kunden drei Parameter übergeben müssen, nämlich: Kanal, Telefon, Zeichen Die anderen Parameter sind die variablen Parameter und Parameterwerte der SMS-Vorlage.


Dann ist der Parameter in der Methode externalMerchantSendMessage(MessageContext param) ein variables Objekt. Gibt es in C# 4.0 nicht eine Dynamik, die zur Beschreibung veränderlicher Objekte verwendet wird?

Dann besteht der erste Schritt darin, den eingehenden Parametertyp zu ändern. Früher war es ein fest codierter, stark typisierter MessageContext. Jetzt wird der Code der externalMerchantSendMessage-Methode wie folgt geändert :

:

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("=", ":&#39;").Replace("&", "&#39;,") + "&#39;}";
                }
                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));
Nach dem Login kopieren

DynamicJsonConverter wird zum Konvertieren von JSON-Strings in Objektobjekte verwendet. Der Code lautet wie folgt:

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("}");
        }
Nach dem Login kopieren

Das Obige ist der Inhalt von a .NET-Code-Rekonstruktion (Teil 1), weitere Informationen zu verwandten Inhalten finden Sie auf der chinesischen PHP-Website (www.php.cn)!


Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage
Über uns Haftungsausschluss Sitemap
Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!