.NET 코드 리팩터링 기억하기(1부)

黄舟
풀어 주다: 2017-02-06 14:37:00
원래의
1206명이 탐색했습니다.

요구 사항: 문자 메시지 전송을 위한 템플릿을 개발하려면 고객마다 서로 다른 템플릿을 사용할 수 있으며 고객마다 사용하는 변수 매개변수도 다릅니다.


긴급 상황을 대비해 온라인으로 문자 메시지를 보낼 수 있는 문자 메시지 템플릿 기능도 완성되었으며, 새로운 기록도 추가되었습니다. 테이블로. 문자 메시지 템플릿을 추가, 삭제, 수정, 확인하는 인터페이스만 만들면 되는데, 숙련된 운전자라면 이 일이 꽤 간단한 것 같습니다.


아래 그림은 원래 생성된 테이블입니다.

.NET 코드 리팩터링 기억하기(1부)

SQL 생성 스크립트는 다음과 같습니다.

.NET 코드 리팩터링 기억하기(1부)

이전에 고객이 전화할 수 있도록 문자 메시지를 보내는 API 인터페이스가 개발되었습니다. 즉, 코드를 발신자(고객)가 수정할 수는 없습니다. 아직 완성되지 않은 작업을 맡는 것을 극도로 꺼려하지만 모든 개발 작업을 처음부터 시작하는 수밖에 없습니다.


엔티티 클래스 코드는 다음과 같습니다.

.NET 코드 리팩터링 기억하기(1부)

DOT 클래스:

.NET 코드 리팩터링 기억하기(1부)

이전 코드이며 비즈니스 엔터티 클래스인 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);
        }
로그인 후 복사

위는 개발 업무를 받기 전 구현했던 함수들입니다. 내 작업은 매우 간단한 것 같지만 수년간의 개발 경험에 따르면 지금은 아무것도 신경 쓰지 않고 SMS 템플릿을 추가, 삭제, 수정 및 확인하기 위한 인터페이스를 만들면 앞으로 유지보수하는 사람들은 분명 미쳐버릴 것입니다.


뭔가 문제가 보이나요?


이 인터페이스 메소드 externalMerchantSendMessage는 모든 고객에 대해 호출되며 고객마다 서로 다른 SMS 템플릿을 사용하고 템플릿마다 변수 매개변수가 다릅니다. 이제 모든 변수 매개변수가 MessageContext 클래스에 캡슐화됩니다. 문제는 모든 변수 매개변수를 한 번에 결정하여 변경하지 않고 유지할 수 없다는 것입니다.


즉, 변수 매개변수를 추가해야 하면 MessageContext 클래스의 코드를 수정해야 하며 GetContent 메서드의 코드는 어렵습니다. 코딩되어 있으므로 이에 따라 수정해야 합니다. 이것이 하나의 순환을 형성하여 끊임없이 변수 매개변수를 추가하고, 끊임없이 코드를 변경하고, 인터페이스 버전을 계속 출시합니다...


시간이 충분하면 자연스럽게 훈련된 프로그래머라면 리팩토링을 시작하세요.


리팩토링을 하기 전에 떠오르는 것은 다양한 디자인 패턴이 아니라 객체지향 디자인의 기본 원칙입니다. 다양한 디자인 패턴은 다양한 무술 루틴이나 동작과 같습니다. 무술 수련자는 태극권을 연습하는 장무지처럼 먼저 다양한 루틴을 배우고 모든 루틴을 잊어서 마스터해야 합니다.


무브는 죽었지만 사람은 살아있고, 모든 무브에는 결점이 있기 때문에 보편적인 디자인 패턴이 없듯이, 어떤 디자인이든 모든 모델에는 단점이 있습니다.


객체지향 디자인의 핵심 아이디어는 변경사항을 캡슐화하는 것이므로 먼저 변경점을 찾아보세요. 위의 분석을 통해 우리는 SMS 템플릿의 가변 매개변수인 변경점을 발견했으며, 이러한 가변 매개변수는 고객 호출자에 의해 전달되며 고객에 따라 전달되는 매개변수 변수는 다를 수 있습니다.


먼저 고객이 전달하는 것은 무엇인지 살펴보겠습니다. 고객 호출 코드를 살펴보겠습니다. 호출 방법에는 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(&#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);
                }
            });
        };
로그인 후 복사

고객이 전달하는 것은 JSON 형식의 객체인 키-값 쌍의 모음임을 알 수 있습니다. 이전 코드 bool isAuth = authModelBusiness.isAuth(param.channel, param.phone, param.sign);에 따르면 모든 통화 고객이 통과해야 하는 세 가지 매개변수, 즉 채널, 전화, 서명이 있음을 분석할 수 있습니다. , 기타 매개변수는 SMS 템플릿의 가변 매개변수와 매개변수 값입니다.


그런 다음 externalMerchantSendMessage(MessageContext param) 메소드의 매개변수는 변수 객체입니다. C# 4.0에는 변경 가능한 개체를 설명하는 데 사용되는 동적 요소가 없나요?

그런 다음 첫 번째 단계는 하드 코딩된 강력한 유형의 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("=", ":&#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));
로그인 후 복사

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 코드 재구성의 내용입니다. (1부) 더 많은 관련 내용을 주목해 주세요. PHP 중국어 사이트(www.php.cn)!


관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿