你定义的类看起来更像是一个随机的值,而不是一个定义明确的类。所有这些值实际上代表什么?
public string StartYear;
public string EndYear;
public string Year;
public DateTime StartDate;
public DateTime EndDate;
public string StartMonth;
public string EndMonth;
public DateTime StartDay;
public DateTime EndDay;
StartDate
例如,和有什么区别StartDay
?StartYear
和是什么StartMonth
?这个类实际上定义了什么?看起来您正在尝试将DateTime
值分解为组件。你不需要这样做。一个简单的DateTime
值将充分存储必要的信息,您可以直接从该值获取组件:
public DateTime StartDate;
public DateTime EndDate;
例如,如果您需要知道月份,您可以从该值中获取它:
myObject.StartDate.Month;
要继续改进该类,您需要使用属性而不是公共成员。在 C# 中,它们看起来像这样:
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
这些被专门称为自动实现的属性。它们是完整属性的编译器简写:
private DateTime _startDate;
public DateTime StartDate
{
get { return _startDate; }
set { _startDate = value; }
}
// repeat for EndDate
属性的好处是该类对其内部结构的暴露较少。如果您需要向类添加任何逻辑(例如检查日期的特定范围,例如确保过去没有 StartDate),那么您可以将其添加到属性中而不会破坏类的二进制兼容性。所以消费代码永远不需要知道区别。例如:
private DateTime _startDate;
public DateTime StartDate
{
get { return _startDate; }
set
{
if (value < DateTime.Now)
throw new ArgumentException(string.Format("Start Date must not be in the past: {0}", value.ToString()));
_startDate = value;
}
}
您可以通过继续定义此类的行为来进一步实现这一点。即使暴露了这些属性,仍然会使类更像是“数据结构”而不是“对象”。(为了进一步了解数据/对象反对称,我推荐 Robert Martin 的 Clean Code。)正确的面向对象设计的目标是让对象隐藏其数据并公开在内部对该数据执行有状态操作的方法.
例如,如果您需要延长EndDate
一天,您可以这样做:
myObject.EndDate += new TimeSpan(1, 0, 0, 0);
但更面向对象的方法(坚持“告诉,不问”原则)是告诉对象本身延长时间,而不是直接告诉其数据延长时间(从而“询问”对象其过程中的数据,可以说也违反了得墨忒耳定律):
myObject.ExtendEndDate(new TimeSpan(1, 0, 0, 0));
甚至:
myObject.ExtendEndDateInDays(1);
您只需要在对象上实现这样的方法,并且该方法将在内部扩展EndDate
.
类本身应该封装它所代表的概念所需的所有功能。如果绝对必要,它可以提供对其内部成员的公共读取访问,但从设计的角度来看,值得问问自己真正需要对对象的数据进行什么样的查询,并为这些查询提供更有针对性的方法,而不是直接访问到类的数据成员。