领域驱动(DDD)实战---月份类YearMonth

前端之家收集整理的这篇文章主要介绍了领域驱动(DDD)实战---月份类YearMonth前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

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

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

[代码] 用Extension的方式,来增强代码流畅性和可读性

  1. public static class YearMonthExtension
  2.     {
  3.         public static YearMonth year(this int year,int month)
  4.         {
  5.             return new YearMonth(year,month);
  6.         }
  7.         public static bool is_later_than(this YearMonth left,YearMonth right) {
  8.             return left.CompareTo(right) > 0;
  9.         }
  10.         public static bool is_ealier_than(this YearMonth left,YearMonth right) {
  11.             return left.CompareTo(right) < 0;
  12.         }
  13.         public static YearMonth get_ealier(this YearMonth left,YearMonth right)
  14.         {
  15.             if (left.is_ealier_than(right))
  16.                 return left;
  17.             return right;
  18.         }
  19.         public static YearMonth get_later(this YearMonth left,YearMonth right)
  20.         {
  21.             if (left.is_later_than(right))
  22.                 return left;
  23.             return right;
  24.         }
  25. }

[代码] 从测试看功能:公用的测试基类,很简单,就是声明一个YearMonth对象做测试

  1. public class YearMonthSpecs
  2. {
  3. protected static YearMonth subject;
  4.  
  5. }

[代码] 通过构造器,创建YearMonth对象

  1. public class When_init_by_year_month
  2. :YearMonthSpecs
  3. {
  4. private Because of =
  5. () => subject = new YearMonth(2011,3);
  6.  
  7. private It year_should_set_properly =
  8. () => subject.Year.ShouldEqual(2011);
  9.  
  10. private It month_should_set_properly =
  11. () => subject.Month.ShouldEqual(3);
  12.  
  13. }

[代码] 通过流畅接口创建YearMonth: 2012.year(3)。你还可以自己定制为: 2012.年(3)

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


[代码] 通过字符串创建

  1. public class When_init_by_string : YearMonthSpecs
  2. {
  3. private Because of =
  4. () => subject = new YearMonth("2011年01月");
  5.  
  6. private It year_should_set_properly =
  7. () =>
  8. {
  9. subject.Year.ShouldEqual(2011);
  10. subject.Month.ShouldEqual(1);
  11. };
  12. }

[代码] Special Case模式,特别处理:世界末日的下一个月还是世界末日,创世纪的上一个月还是创世纪

  1. private It far_past_last_month_is_still_far_past =
  2. () => YearMonth.FarPast.get_last().ShouldEqual(YearMonth.FarPast);
  3. private It far_past_next_month_is_still_far_past =
  4. () => YearMonth.FarPast.get_next().ShouldEqual(YearMonth.FarPast);
  5.  
  6. private It far_future_last_month_is_stil_far_future =
  7. () => YearMonth.FarFuture.get_last().ShouldEqual(YearMonth.FarFuture);
  8.  
  9. private It far_future_next_month_is_stil_far_future =
  10. () => YearMonth.FarFuture.get_next().ShouldEqual(YearMonth.FarFuture);

YearMonth结构类型的完整代码

  1. using System;
  2. using Skight.Arch.Domain.Interfaces;
  3.  
  4. namespace Skight.Arch.Domain.Entities
  5. {
  6. public struct YearMonth : IEquatable<YearMonth>,IComparable<YearMonth>
  7. {
  8. private readonly int ticks;
  9. private readonly int year;
  10. private readonly int month;
  11. private const int MONTHS_PER_YEAR=12;
  12.  
  13. public static YearMonth FarPast = new YearMonth(0,1);
  14. public static YearMonth FarFuture = new YearMonth(9999,12);
  15. #region Constructors by ticks,year/month and datetime
  16. internal YearMonth(int ticks)
  17. {
  18. this.ticks = ticks;
  19. int remain;
  20. year = Math.DivRem(ticks-1,MONTHS_PER_YEAR,out remain);
  21. month = remain + 1;
  22. }
  23. public YearMonth(int year,int month)
  24. :this(year*MONTHS_PER_YEAR + month){}
  25. public YearMonth(DateTime date_time)
  26. :this(date_time.Year,date_time.Month){}
  27.  
  28. public YearMonth(string yearMonth):this(int.Parse(yearMonth.Substring(0,4)),int.Parse(yearMonth.Substring(5,2)))
  29. {}
  30.  
  31. #endregion
  32.  
  33. public int Year { get { return year; } }
  34. public int Month { get { return month; } }
  35. public DateTime as_date_Time()
  36. {
  37. return new DateTime(Year,Month,1);
  38. }
  39.  
  40. public override string ToString()
  41. {
  42. return string.Format("{0}年{1}月",year.ToString("0000"),month.ToString("00"));
  43. }
  44.  
  45. #region Euqals and Compare
  46. public bool Equals(YearMonth other)
  47. {
  48. return other.ticks == ticks;
  49. }
  50.  
  51. public override bool Equals(object obj)
  52. {
  53. if (ReferenceEquals(null,obj)) return false;
  54. if (obj.GetType() != typeof (YearMonth)) return false;
  55. return Equals((YearMonth) obj);
  56. }
  57.  
  58. public override int GetHashCode()
  59. {
  60. return ticks;
  61. }
  62.  
  63. public int CompareTo(YearMonth other)
  64. {
  65. return ticks.CompareTo(other.ticks);
  66. }
  67.  
  68. #endregion
  69.  
  70. #region Discrete interface
  71. public YearMonth get_last()
  72. {
  73. if (Equals(FarPast))
  74. return FarPast;
  75.  
  76. if (Equals(FarFuture))
  77. return FarFuture;
  78. return new YearMonth(ticks - 1);
  79. }
  80. public YearMonth get_last(int Dvalue)
  81. {
  82. if (Equals(FarPast))
  83. return FarPast;
  84.  
  85. if (Equals(FarFuture))
  86. return FarFuture;
  87. return new YearMonth(ticks - Dvalue);
  88. }
  89.  
  90. public YearMonth get_next()
  91. {
  92. if (Equals(FarPast))
  93. return FarPast;
  94.  
  95. if (Equals(FarFuture))
  96. return FarFuture;
  97. return new YearMonth(ticks + 1);
  98. }
  99.  
  100. public YearMonth get_next(int DValue)
  101. {
  102. if (Equals(FarPast))
  103. return FarPast;
  104.  
  105. if (Equals(FarFuture))
  106. return FarFuture;
  107. return new YearMonth(ticks + DValue);
  108. }
  109. #endregion
  110.  
  111. public static implicit operator DateTime(YearMonth year_month)
  112. {
  113. return year_month.as_date_Time();
  114. }
  115.  
  116. public static implicit operator YearMonth(DateTime date_time)
  117. {
  118. return new YearMonth(date_time);
  119. }
  120. }
  121. }


(本文版权属于© 2012 - 2013 予沁安 | 转载请注明作者和出处

猜你在找的设计模式相关文章