好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

领域驱动(DDD)实战1

领域驱动(DDD)实战1

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

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

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

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

?

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;

         }

}

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

?

public   class   YearMonthSpecs

     {

         protected   static   YearMonth subject;

 

     }

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

?

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);

 

     }

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

?

public   class   When_create_year_month_through_fluent_interface

     {

         private   It should_create_year_month_properly =

             () => 2012.year(3).ShouldEqual( new   YearMonth(2012, 3));

     }

[代码]  通过字符串创建

?

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);

                  };

     }

 

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

?

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);

YearMonth结构类型的完整代码

?

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);

         }

     }

}


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

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于领域驱动(DDD)实战1的详细内容...

  阅读:40次