范围

代表一系列值

2004年3月07日

这是其中的一部分进一步的企业应用程序架构开发188比分直播网 坚持原创写作我在2000年中期正在做。可悲的是,太多了许多其他事情已经引起了我的关注,所以我还有时间进一步努力,也没有看到可预见的未来的时间。因此,这种材料在草案表格中非常非常多,直到我能够在进行时间才能再次执行任何更正或更新。

看到与一系列值检查值的比较非常常见。范围通常由一对值处理,并检查它们两者。范围而是使用单个对象作为一个整体来表示范围,然后提供相关操作来测试是否值落在范围内,并比较范围。

这个怎么运作

基本类很简单。您有一个包含两个字段的类,代表范围的开始和结束。您还提供了一个包含测试,以查看提供的值是否在范围内。

您可以使用范围对于任何支持比较操作的类型,这都相当于<、>、=、<=和>=。根据语言和类型的不同,您可能获得也可能得不到这些精确的运算符,但是您需要类型上的等价关系,也就是说您需要有一些默认的排序标准,允许您对值进行排序。

图1:使用参数化类型表示法显示UML中的范围

Range是参数化类的一个明显的选择图1,如果你的语言支持这一点。在UML术语中,您可以通过使用Range和Range类型的类来显示不同类型的范围。这只是数字范围和日期范围的建模简写。因此,许多人,包括我自己,更喜欢避免奇怪的名称,而只是使用像数字范围和数据范围这样的术语。

一个更复杂的范围可以设置排序标准。通常,这可以是能够排序在该范围内使用的类型的实例的任何功能。排序标准本质上是一种函数,或包裹函数的对象。

你可能会有一些开放的范围(例如大于6)。有几种方法可以解决这个问题。一种是将空值视为无限。您的范围检查代码将变得有点复杂,但是您可以对用户隐藏这一点。另一种选择是特例对于极端情况(如正无穷大)。无论您做出何种选择,都可以通过创建表单的方法对该类的用户隐藏Range.Greaterthan(6)。

如果您的类型传统是连续的(例如,实数),而不是离散(如整数或日期),您需要其他信息来判断上层或下部是否在范围内。使用整数,您可以通过将较低的七个设置为大于六个范围。但是,您不希望使用6.0000000000001的实数。使用几个布尔标记。

以及测试的操作,如果值在范围内,则还可以包括比较范围的操作:如果一个范围触摸另一个范围,或者一个范围包括另一个范围,则可以判断它们是否可以判断另一个范围。当您需要执行类似检查某些范围子集的情况时,这些都可以非常有帮助。

Range类显然适合于参数化类,如果您的语言使用它们的话。如果不是,您将面临基于抽象类构建它们或为特定情况创建专门化的子类型的问题。如果您可能为了其他目的而获取上值和下值,那么向下转换的痛苦足以让您最好创建一个具体的range类。

在思考范围时,我发现最常见的方法是开始和结束。然而,具有开始和长度,甚至结束和长度同样有用。您也可以拥有所有三个:开始,结束和长度,具有值之间的明显约束。

何时使用它

范围这是我一直在使用的模式。编写适当的范围类很容易,而且一旦这样做了,使用范围比使用值对更容易。在建模时,使用范围比使用成对更显式——而且同样直观。

示例:日期范围(Java)

作为一个例子,我将使用日期范围。这是一个需要使用的常见范围,并且允许我巧妙地避开连续范围的额外复杂性。我没有使用Java的标准日期,而是使用我自己的日期类,它只具有日期精度(请参阅时间点

基本构造函数和访问者非常简单。

类DateRange……

公共Daterange(日期开始,日期结束){这个(新的mfdate(start),new mfdate(end));公共Daterange(MFdate Start,MFdate End){this.start = start;这个=结束;}

类DateRange……

公共MFdate End(){返回端;public mfdate start(){返回开始;public string toString(){if(igempty())返回“空日期范围”;返回start.tostring()+“ - ”+ end.tostring();public boolean isempty(){返回start.After(END);}

任何使用中提供的关键方法范围是包含方法。

类DateRange……

公共布尔包括(mfdate arg){return!arg.before(start)&&!arg.After(END);}

我喜欢为开放式范围和空范围提供额外的构造函数。

类DateRange……

public static DateRange upTo(MfDate end) {return new DateRange(MfDate. MfDate. MfDate. MfDate. MfDate. MfDate. MfDate. MfDate. MfDate. MfDate。过去,结束);} public static DateRange startingOn(MfDate start) {return new DateRange(start, MfDate. future);} public static DateRange EMPTY = new DateRange(new MfDate(2000,4,1), new MfDate(2000,1,1));

提供允许您比较范围的操作是有用的。

类DateRange……

公共布尔等于(Object arg){if(!(arg instanceof daterance))返回false;daterange其他=(daterange)arg;返回start.equals(其他.start)&& end.equals(其他.end);public int hashcode(){return start.hashcode();公共布尔重叠(daterange arg){return arg.includes(start)||arg.includes(结束)||这个.Cludes(arg);公共布尔包括(daterange arg){return this.includes(arg.start)&& this.includes(arg.end);}

对于大多数应用程序,这就是您所需要的。但某些情况表明其他有用的行为。一个可以找出两个范围之间存在的差距。

类DateRange……

公共Daterange差距(Daterange Arg){如果(替补(arg))返回daterange.preasty;daterange较低,更高;if(this.compareto(arg)<0){较低=这个;更高= arg;}否则{dight = arg;更高=这个;}返回新的Daterange(Lower.end.adddays(1),更高版本.start.adddays(-1));public int compareto(对象arg){daterange其他=(daterange)arg;if(!start.equals(stoot.start))返回start.compareto(其他.start);返回End.Compareto(其他); }

另一个是检测两个日期是否彼此邻接。

类DateRange……

public boolean abuts(DateRange arg) {return !this.overlaps(arg) && this.gap(arg).isEmpty();}

并查看一组范围是否完全分区另一个范围。

类DateRange……

公共布尔分区(Daterange [] args){if(!IsContiuuous(args))返回false;返回这一点.Equals(daterand.Combination(args));公共静态daterange组合(Daterange [] args){arrays.sort(args);if(!IsContiue(args))抛出新的IllegalArgumentException(“无法组合日期范围”);返回新的daterange(args [0] .start,args [args.length -1]。}公共静态布尔不连续(daterange [] args){arrays.sort(args);for(int i = 0; i