当前访客身份:游客 [ 登录 | 加入开源中国 ]

代码分享

当前位置:
代码分享 » C#  » 编程基础
分享到: 
收藏 +0
2
.Net中有一个DateTime结构类,涉及时间和日期,这个类大量使用。可是,他的名称已经显著的表明他是表达某个具体的时刻。当我们不需要每天的具体时间时,如:我的程序逻辑仅仅需要年月(发工资的周期?),这个DateTime显得有些累赘,甚至不合用。
一般人们解决的方式,仍然使用DateTime而从数据上,设置hour,mintue等等为0。 然而,这与DDD的理念相背,名称有与含义有偏差,另外,数据一致性的维护,散布在各个角落,如,保证日期始终为1,小时,分钟为0。另外,与月份相关的功能,如:得到下一个月份,要么用DateTime本身的功能(AddMonths),要么提炼出一个Utitlies出来。 前者,需要开发者时刻重复DateTime到YearMonth的映射逻辑,后者是个反模式。

这里,我创建出一个基本类型YearMonth,可以作为代码的基本砖块。
标签: <无>

代码片段(10) [全屏查看所有代码]

1. [代码]YearMonth结构类型的完整代码     跳至 [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [全屏预览]

using System;
using Skight.Arch.Domain.Interfaces;

namespace Skight.Arch.Domain.Entities
{
    public struct YearMonth : IEquatable<YearMonth>, IComparable<YearMonth>
    {
        private readonly int ticks;
        private readonly int year;
        private readonly int month;
        private const int MONTHS_PER_YEAR=12;

        public static YearMonth FarPast = new YearMonth(0,1);
        public static YearMonth FarFuture = new YearMonth(9999,12);
        #region Constructors by ticks, year/month and datetime
        internal YearMonth(int ticks)
        {
            this.ticks = ticks;
            int remain;
            year = Math.DivRem(ticks-1, MONTHS_PER_YEAR, out remain);
            month = remain + 1;
        }
        public YearMonth(int year, int month)
            :this(year*MONTHS_PER_YEAR + month){}
        public YearMonth(DateTime date_time)
            :this(date_time.Year,date_time.Month){}

        public YearMonth(string yearMonth):this(int.Parse(yearMonth.Substring(0, 4))
            ,int.Parse(yearMonth.Substring(5, 2)))
        {}

        #endregion 

        public int Year { get { return year; } }
        public int Month { get { return month; } }
        public DateTime as_date_Time()
        {
            return new DateTime(Year,Month,1);
        }

        public override string ToString()
        {
            return string.Format("{0}年{1}月", year.ToString("0000"), month.ToString("00"));
        }

        #region Euqals and Compare
        public bool Equals(YearMonth other)
        {
            return other.ticks == ticks;
        }


        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj)) return false;
            if (obj.GetType() != typeof (YearMonth)) return false;
            return Equals((YearMonth) obj);
        }

        public override int GetHashCode()
        {
            return ticks;
        }

        public int CompareTo(YearMonth other)
        {
            return ticks.CompareTo(other.ticks);
        }

        #endregion

        #region Discrete interface
        public YearMonth get_last()
        {
            if (Equals(FarPast))
                return FarPast;

            if (Equals(FarFuture))
                return FarFuture;
            return new YearMonth(ticks - 1);
        }
        public YearMonth get_last(int Dvalue)
        {
            if (Equals(FarPast))
                return FarPast;

            if (Equals(FarFuture))
                return FarFuture;
            return new YearMonth(ticks - Dvalue);
        }

        public YearMonth get_next()
        {
            if (Equals(FarPast))
                return FarPast;

            if (Equals(FarFuture))
                return FarFuture;
            return new YearMonth(ticks + 1);
        }

        public YearMonth get_next(int DValue)
        {
            if (Equals(FarPast))
                return FarPast;

            if (Equals(FarFuture))
                return FarFuture;
            return new YearMonth(ticks + DValue);
        }
        #endregion 

         public static implicit operator DateTime(YearMonth year_month)
         {
             return year_month.as_date_Time();
         }

        public static implicit operator YearMonth(DateTime date_time)
        {
            return new YearMonth(date_time);
        }
    }
}

2. [代码]用Extension的方式,来增强代码流畅性和可读性     跳至 [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [全屏预览]

 public static class YearMonthExtension
    {
        public static YearMonth year(this int year, int month)
        {
            return new YearMonth(year, month);
        }

        public static bool is_later_than(this YearMonth left, YearMonth right) {
            return left.CompareTo(right) > 0;
        }

        public static bool is_ealier_than(this YearMonth left, YearMonth right) {
            return left.CompareTo(right) < 0;
        }

        public static YearMonth get_ealier(this YearMonth left, YearMonth right)
        {
            if (left.is_ealier_than(right))
                return left;
            return right;
        }

        public static YearMonth get_later(this YearMonth left, YearMonth right)
        {
            if (left.is_later_than(right))
                return left;
            return right;
        }
}

3. [代码]从测试看功能:公用的测试基类,很简单,就是声明一个YearMonth对象做测试     跳至 [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [全屏预览]

public class YearMonthSpecs
    {
        protected static YearMonth subject;

    }

4. [代码]通过构造器,创建YearMonth对象     跳至 [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [全屏预览]

public class When_init_by_year_month
        :YearMonthSpecs
    {
        private Because of =
            () => subject = new YearMonth(2011,3);

        private It year_should_set_properly =
            () => subject.Year.ShouldEqual(2011);

         private It month_should_set_properly =
             () => subject.Month.ShouldEqual(3);

    }

5. [代码]通过流畅接口创建YearMonth: 2012.year(3)。你还可以自己定制为: 2012.年(3)     跳至 [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [全屏预览]

public class When_create_year_month_through_fluent_interface
    {
        private It should_create_year_month_properly =
            () => 2012.year(3).ShouldEqual(new YearMonth(2012, 3));
    }

6. [代码]通过字符串创建     跳至 [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [全屏预览]

public class When_init_by_string : YearMonthSpecs
    {
        private Because of =
            () => subject = new YearMonth("2011年01月");

        private It year_should_set_properly =
             () =>
                 {
                     subject.Year.ShouldEqual(2011);
                     subject.Month.ShouldEqual(1);
                 };
    }

7. [代码]通过DateTime创建YearMonth     跳至 [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [全屏预览]

 public class When_init_by_date_time
        : YearMonthSpecs {
         private Because of =
             () => subject = new YearMonth(new DateTime(2011,3,2));

         private It year_should_set_properly =
             () => subject.Year.ShouldEqual(2011);

         private It month_should_set_properly =
             () => subject.Month.ShouldEqual(3);

     }

8. [代码]比较两个YearMonth的早和晚,用阅读性更强的单词 is_later_than(), is_earlier_than()     跳至 [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [全屏预览]

 public class When_test_later_ealier
    {
        private It greater_should_be_later =
            () => 2011.year(12).is_later_than(2010.year(1)).ShouldBeTrue();

        private It less_should_be_ealier =
            () => 2010.year(1).is_ealier_than(2012.year(12)).ShouldBeTrue();
    }

9. [代码]上一个月,下一个月的功能:get_last(), get_next()     跳至 [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [全屏预览]

  private It Feburary_last_month_should_be_January =
           () => new YearMonth(2011, 2).get_last().ShouldEqual(new YearMonth(2011, 1));

        private It January_last_month_should_be_December_of_last_year =
            () => new YearMonth(2011, 1).get_last().ShouldEqual(new YearMonth(2010, 12));

        private It December_next_month_should_be_January_in_next_year =
            () => new YearMonth(2011, 12).get_next().ShouldEqual(new YearMonth(2012, 1));

        private It May_next_month_should_be_June_in_next_year =
           () => new YearMonth(2011, 5).get_next().ShouldEqual(new YearMonth(2011, 6));

10. [代码]Special Case模式,特别处理:世界末日的下一个月还是世界末日,创世纪的上一个月还是创世纪     跳至 [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [全屏预览]

private It far_past_last_month_is_still_far_past =
            () => YearMonth.FarPast.get_last().ShouldEqual(YearMonth.FarPast);
        private It far_past_next_month_is_still_far_past =
         () => YearMonth.FarPast.get_next().ShouldEqual(YearMonth.FarPast);

        private It far_future_last_month_is_stil_far_future =
          () => YearMonth.FarFuture.get_last().ShouldEqual(YearMonth.FarFuture);

        private It far_future_next_month_is_stil_far_future =
            () => YearMonth.FarFuture.get_next().ShouldEqual(YearMonth.FarFuture);


开源中国-程序员在线工具:Git代码托管 API文档大全(120+) JS在线编辑演示 二维码 更多»