매개 변수 대상을 통해 남겨진 코드에 의미를 가져오다


내가 연구한 대부분의 유류 코드 라이브러리는 원시적인 어려움을 겪었다.그 중 하나는 한 그룹int, string 또는 bool 파라미터가 존재하는 방법이다.이 방법들은 코드 라이브러리를 손상시켰다. 이해하기 어렵고 오용하기 쉽기 때문이다. 버그와 두통을 초래할 수도 있다.본고는 매개 변수의 대상을 사용함으로써 이 문제에 대해 간단하지만 매우 효과적인 해결 방안을 제공하는 데 목적을 두고 있다.
다음 방법으로 서명하여 설명합니다.
string GenerateLoginLink(
    int userId, 
    DateTime? expiryDate, 
    int? maxAllowedClicks, 
    bool notifyOnClick, 
    bool sendLinkByEmail, 
    bool redirectToHomePage, 
    string? redirectUrl
);
이 방법은 사용자가 플랫폼에 로그인하고 특정 URL로 방향을 바꿀 수 있는 링크를 생성합니다.이 링크는 유효기간이나 허용된 최대 클릭 횟수가 있습니다.또한 전자 메일을 통해 사용자에게 직접 보내고 사용자가 클릭할 때 관리자에게 알릴 수도 있습니다.
다음과 같은 몇 가지 비즈니스 규칙을 고려해야 합니다.
  • expiryDatemaxAllowedClicks는 서로 배척한다(즉, 우리는 그 중 하나를 매개 변수로만 통과할 수 있다)
  • redirectUrlredirectToHomePage인 경우에만 유용
  • 현재 이런 방법은 몇 가지 문제를 제기했다.

  • 불법 조합.최상의 경우, 이 방법에 대해 하나 false 와 하나 expiryDate 를 제공하면 이상을 일으키거나, 그 중 한 필드를 자동으로 우선적으로 처리할 수 있습니다.최악의 경우 사건이 처리되지 않았기 때문에 예측할 수 없는 행동을 할 수 있다.그리고 둘 다maxAllowedClicks라면?

  • 표현력이 약하다.상술한 상업 규칙은 결코 명백히 알 수 있는 것이 아니다.아마도 그것들은 방법의 주석에 기록되어 있을 것이다. 그러나 사람들은 항상 문서를 읽지 않는다. 만약 우리가 문서를 업데이트하는 것을 잊어버리면 문서는 곧 유행이 지났을 것이다. (아마도 이것이 사람들이 문서를 무시하는 경향이 있는 이유일 것이다.)개발자가 불법이나 무용한 조합을 통과하는 것을 막을 수 있는 것은 절대 없다.

  • 실수하기 쉽다.마지막으로, 당신은 방법 서명 중의 3개의 연속 브리 값을 알아차렸습니까?그중 두 개를 잘못 뒤바꾸면 얼마나 쉬울까요?이 방법은 완전히 예상한 작업에 따라 철저한 단원 테스트를 거칠 수 있으며, 잘못 사용하면 버그가 발생할 수 있습니다.
  • 첫 번째 교체는 이 방법의 매개 변수 대상을 사용할 것이다.
    public class LoginLinkConfig 
    {
        public DateTime? ExpiryDate {get; set;}
        public int? MaxAllowedClicks {get; set;}
        public bool NotifyOnClick {get; set;}
        public bool SendLinkByEmail {get; set;}
        public bool RedirectToHomePage {get; set;}
        public string? RedirectUrl {get; set;}
    }
    
    string GenerateLoginLink(int userId, LoginLinkConfig config);
    
    이런 변화는 오류의 위험을 낮출 수 있고 기본값의 사용을 더욱 쉽게 할 수 있다.그러나 이는 불법 조합을 막고 표현력을 높이는 데 큰 도움이 되지 않는다.
    이 문제들을 해결하는 방법 중 하나는builder 모드를 사용하는 것이다.이 모드는 선택적 필드가 있는 객체에 특히 유용한 객체를 작성하는 데 사용되는 표현식 API를 제공합니다.
    public class LoginLinkConfig 
    {
        // Properties are now read-only
        public DateTime? ExpiryDate {get;}
        public int? MaxAllowedClicks {get;}
        public bool NotifyOnClick {get;}
        public bool SendLinkByEmail {get;}
        public bool RedirectToHomePage {get;}
        public string? RedirectUrl {get;}
    
        // The constructor is private to force the use of the builder
        private LoginLinkConfig(DateTime? expiryDate, int? maxAllowedClicks, bool notifyOnClick, bool sendLinkByEmail, bool redirectToHomePage, string? redirectUrl) 
        {
            ExpiryDate = expiryDate;
            MaxAllowedClicks = maxAllowedClicks;
            NotifyOnClick = notifyOnClick;
            SendLinkByEmail = sendLinkByEmail;
            RedirectUrl = redirectUrl;
        }
    
        // Notice that the parameter in these methods is not nullable
        public static Builder ExpiringLink(DateTime expiryDate) => new Builder(expiryDate);
        public static Builder LimitedClicksLink(int maxAllowedClicks) => new Builder(maxAllowedClicks);
    
        public class Builder
        {
            private DateTime? _expiryDate;
            private int? _maxAllowedClicks;
            private bool _notifyOnClick;
            private bool _sendLinkByEmail;
            // We can set sensible default values
            private bool _redirectToHomePage = true;
            private string? _redirectUrl;
    
            public Builder(DateTime expiryDate)
            {
                _expiryDate = expiryDate;
            }
    
            public Builder(int maxAllowedClicks)
            {
                _maxAllowedClicks = maxAllowedClicks;
            }
    
            public Builder WithRedirection(string redirectUrl)
            {
                _redirectToHomePage = false;
                _redirectUrl = redirectUrl;
    
                // Return the builder to allow chaining
                return this;
            }
    
            public Builder WithClickNotification()
            {
                _notifyOnClick = true;
    
                // Return the builder to allow chaining
                return this;
            }
    
            public Builder SentByEmail()
            {
                _sendLinkByEmail = true;
    
                // Return the builder to allow chaining
                return this;
            }
    
            public LoginLinkConfig Build() => new LoginLinkConfig(_expiryDate, _maxAllowedClicks, _notifyOnClick, _sendLinkByEmail, _redirectUrl);
        }
    
    }
    
    이 생성기가 있으면 설정 대상을 만들 수 있습니다.
    var maxAllowedClicksConfig = new LoginLinkConfig 
    {
        MaxAllowedClicks = 1,
        NotifyOnClick = true,
        RedirectToHomePage = false,
        RedirectUrl = "/myaccount"
    };
    
    var expiringLinkConfig = new LoginLinkConfig 
    {
        ExpiryDate = DateTime.Now.AddDays(1),
        SendLinkByEmail = true,
        RedirectToHomePage = true
    };
    
    대상
    var maxAllowedClicksConfig = LoginLinkConfig.LimitedClicksLink(1)
        .WithClickNotification()
        .WithRedirection("/myaccount")
        .Build();
    
    var expiringLinkConfig = LoginLinkConfig.ExpiringLink(DateTime.Now.AddDays(1))
        .SendByEmail()
        .Build();
    
    이 새로운 실례화 과정은 더욱 지루하다고 말할 수 있지만 다음과 같은 장점이 있다.

  • 더 의미가 있다.생성기를 사용하면 개발자가 그들의 뜻을 표현할 수 있다는 것은 의심의 여지가 없다.우리는 모호성을 없앴기 때문에 오류가 발생할 가능성이 더욱 적다.

  • 불법 국가는 없다.예에서 보듯이 불법 국가를 대표할 방법은 절대 없다.예를 들어 만료된 링크를 만들려면 동시에 설정할 수 없습니다null.그렇지 않으면 _maxAllowedClicks를 제공할 때 redirectUrl는 자동으로 _redirectToHomePage로 설정되며 변경할 수 없습니다.

  • 더욱 간단하게 실현하다.마지막으로, 위에서 기술한 업무 규칙이 대상 생성에 삽입되어 있기 때문에, 그것들을 방법에 강제로 집행할 필요가 없다. 이것은 더욱 간단하게 실현할 수 있다.이 밖에 다른 방법도 config 대상을 사용할 수 있다. 왜냐하면 업무 규칙이 시종 적용될 것이라는 것을 알고 있기 때문이다.
  • 전반적으로parameter 대상과builder 모드를 결합하여 사용하는 것은 매우 간단한 방법으로 의미를 남겨진 코드 라이브러리로 되돌려주고 불법 상태를 실제적으로 표시할 수 없게 함으로써 버그를 줄일 수 있다.

    좋은 웹페이지 즐겨찾기