它山之玉可以重構:社會安全號碼碼解析、驗證工具3(第三天)

來源:互聯網
上載者:User

前兩天的進度似乎有些慢,今天加快了一點, 不把每一步說的那麼詳細了.

==》地區資訊的提取

繼性別和生日之後,最後一個資訊塊,只是列出測試如下.


(本文著作權屬於 2012 - 2013 予沁安)

==》有效性

這是一個比較大的問題. 前面,我臨時性的把不同地方的驗證去掉了. 代碼原作者也過來, 暢敘了他關於驗證的看法. 他是對的, 這種完全驗證的方式,根本上說是 DDD的設計思想。不過,想我所說,我知識臨時性的去掉,保證測試的單元性。驗證的功能,由驗證的測試來驅動。而第二點考慮,我的驗證打算放在構造器中,也就是說,如果,有任何錯誤的輸入,連第一道門都進不來。

這裡,測試和實現都很簡單,看起來很多,只是一些羅列,不同的錯誤情境而已。

[Subject("身份證,有效性")]    public class when_create_social_id_with_valid_format {        private Because of = () => subject = new SocialID("430103123456780020");        private It should_create_social_properly =            () => subject.getCardNumber().ShouldEqual("430103123456780020");        private static SocialID subject;    }    [Subject("身份證,有效性")]    public class when_create_social_id_with_null_string {        private Because of = () =>exception= Catch.Exception(()=>new SocialID(null));        private It should_not_allow_to_create =            () =>exception.ShouldNotBeNull();        private static SocialID subject;        private static Exception exception;    }    [Subject("身份證,有效性")]    public class when_create_social_id_with_empty_string {        private Because of = () => exception = Catch.Exception(() => new SocialID(string.Empty));        private It should_not_allow_to_create =            () => exception.ShouldNotBeNull();        private static SocialID subject;        private static Exception exception;    }    [Subject("身份證,有效性")]    public class when_create_social_id_with_2_length_string {        private Because of = () => exception = Catch.Exception(() => new SocialID("12"));        private It should_not_allow_to_create =            () => exception.ShouldNotBeNull();        private static SocialID subject;        private static Exception exception;    }    [Subject("身份證,有效性")]    public class when_create_social_id_with_20_length_string {        private Because of = () => exception = Catch.Exception(() => new SocialID("12345678901234567890"));        private It should_not_allow_to_create =            () => exception.ShouldNotBeNull();        private static SocialID subject;        private static Exception exception;    }    [Subject("身份證,有效性")]    public class when_create_social_id_alphet_length_string {        private Because of = () => exception = Catch.Exception(() => new SocialID("A23456789012345678"));        private It should_not_allow_to_create =            () => exception.ShouldNotBeNull();        private static SocialID subject;        private static Exception exception;    }

實現

public SocialID(String cardNumber)        {            if (string.IsNullOrEmpty(cardNumber))                throw new ApplicationException("Card Number is empty");            if (cardNumber.Length != CARD_NUMBER_LENGTH)                throw new ApplicationException("Card Number Length is wrong.");            if (!SOCIAL_NUMBER_PATTERN.IsMatch(cardNumber))                throw new ApplicationException("Card Number has wrong charactor(s).");                  }
==》驗證碼

驗證碼是個特殊的有效性檢查,較為複雜,我這裡,把這部分邏輯代碼提煉出來成為一個驗證器。

測試極其簡單,和實現幾乎原封不動。

測試:

public class when_verify_soical_number:Specification<Verifier>    {        Because of = () => { code = subject.verify("43010319791211453"); };        private It verify_code_should_match =            () => code.ShouldEqual('4');        private static char code;    }

實現

namespace Skight.eLiteWeb.Domain.Specs.Properties{    public class Verifier    {        private static char[] VERIFY_CODE =            {                '1', '0', 'X', '9', '8', '7',                '6', '5', '4', '3', '2'            };        /**         * 18位身份證中,各個數位產生校正碼時的權值         */        private static int[] VERIFY_CODE_WEIGHT =            {                7, 9, 10, 5, 8, 4, 2, 1,                6, 3, 7, 9, 10, 5, 8, 4, 2            };        private static int CARD_NUMBER_LENGTH = 18;        public char verify(string source)        {            /**             * <li>校正碼(第十八位元):<br/>             * <ul>             * <li>十七位元字本體碼加權求和公式 S = Sum(Ai * Wi), i = 0...16 ,先對前17位元字的權求和;             * Ai:表示第i位置上的社會安全號碼碼數字值 Wi:表示第i位置上的加權因子 Wi: 7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4             * 2;</li>             * <li>計算模 Y = mod(S, 11)</li>             * <li>通過模得到對應的校正碼 Y: 0 1 2 3 4 5 6 7 8 9 10 校正碼: 1 0 X 9 8 7 6 5 4 3 2</li>             * </ul>             *              * @param cardNumber             * @return             */            int sum = 0;            for (int i = 0; i < CARD_NUMBER_LENGTH - 1; i++)            {                char ch = source[i];                sum += ((int) (ch - '0'))*VERIFY_CODE_WEIGHT[i];            }            return VERIFY_CODE[sum%11];        }    }}

這時候,身份證構造器的完整實現就變成了

public SocialID(String cardNumber)        {            if (string.IsNullOrEmpty(cardNumber))                throw new ApplicationException("Card Number is empty");            if (cardNumber.Length != CARD_NUMBER_LENGTH)                throw new ApplicationException("Card Number Length is wrong.");            if (!SOCIAL_NUMBER_PATTERN.IsMatch(cardNumber))                throw new ApplicationException("Card Number has wrong charactor(s).");            if (cardNumber[CARD_NUMBER_LENGTH - 1] != verifier.verify(cardNumber))                throw new ApplicationException("Card Number verified code is not match.");            this.cardNumber = cardNumber;        }

至此,代碼已經很乾淨了。 是的,還有進一步的改進,如,3個元素(地區,生日,性別)的提煉應該移到構造器中,各個提取的功能就變成了,簡單的資料讀取。Social 的類型,不是class而是struct,因為這是典型的Value Object。 另外,我把15轉18位的部分也去掉了,這可以看作一個Utilit,可以在外部做,不是核心功能。

你,是否能繼續了?

最後,欣賞一下測試結果:


完整代碼:

SocialID.cs

Verifier.cs

(本文著作權屬於 2012 - 2013 予沁安 | 轉載請註明作者和出處)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.