我自己也一直在思考这个问题。到目前为止,这是我的松散想法,我想知道其他人的想法。
谷歌和雅虎的地理编码服务都使用 xAL(及其包含个人姓名的姐妹 XNAL),这给了它一定的权重。但是由于可以在 xAL 中以许多不同的方式描述相同的地址——有些方式比其他方式更具体——所以我看不出 xAL 本身是如何成为数据存储的可接受格式。但是,可以使用其中的一些字段名称,但实际上,在我公司运送到的 16 个国家/地区中,唯一可以使用的基本格式如下:
enum address-fields
{
name,
company-name,
street-lines[], // up to 4 free-type street lines
county/sublocality,
city/town/district,
state/province/region/territory,
postal-code,
country
}
这很容易映射到单个数据库表中,只允许在大多数列上使用 NULL。这似乎是亚马逊和许多组织实际存储地址数据的方式。所以剩下的问题是我应该如何在程序员和任何 GUI 代码都可以轻松使用的对象模型中对此进行建模。我们是否有一个基Address
类型以及每种地址类型的子类,例如AmericanAddress
、CanadianAddress
、GermanAddress
等等?这些地址类型中的每一个都知道如何格式化自己,并且可以选择了解一些关于字段验证的信息。
它们还可以返回有关每个字段的某种类型的元数据,例如以下伪代码数据结构:
structure address-field-metadata
{
field-number, // corresponds to the enumeration above
field-index, // the order in which the field is usually displayed
field-name, // a "localized" name; US == "State", CA == "Province", etc
is-applicable, // whether or not the field is even looked at / valid
is-required, // whether or not the field is required
validation-regex, // an optional regex to apply against the field
allowed-values[] // an optional array of specific values the field can be set to
}
事实上,我们可以采用稍微不那么面向对象的方法,让Address
对象避开 .NET 属性并使用AddressStrategy
来确定格式和验证规则,而不是为每个国家/地区创建单独的地址对象:
object address
{
set-field(field-number, field-value),
address-strategy
}
object address-strategy
{
validate-field(field-number, field-value),
cleanse-address(address),
format-address(address, formatting-options)
}
设置字段时,该Address
对象将在其内部AddressStrategy
对象上调用适当的方法。
使用SetField()
方法方法而不是使用 getter 和 setter 的属性的原因是,代码更容易以通用方式实际设置这些字段,而无需诉诸反射或 switch 语句。
你可以想象这个过程是这样的:
- GUI 代码调用工厂方法或类似方法来创建基于国家/地区的地址。(因此,国家下拉菜单是客户选择的第一件事,或者根据文化信息或 IP 地址为他们预先选择了一个很好的猜测。)
- GUI 调用
address.GetMetadata()
或类似方法并接收AddressFieldMetadata
如上所述的结构列表。它可以使用此元数据来确定要显示的字段(忽略那些is-applicable
设置为false
的字段),标记这些字段的内容(使用field-name
成员),以特定顺序显示这些字段,并对该数据执行粗略的演示级别验证(使用is-required
、validation-regex
和allowed-values
成员)。
- GUI使用(对应于上面的枚举)及其给定值调用该
address.SetField()
方法。field-number
然后,Address
对象或其策略可以对这些字段执行一些高级地址验证,调用地址清理器等。
如果我们想让Address
对象本身在创建后表现得像一个不可变对象,则上述内容可能会略有不同。(我可能会尝试这样做,因为Address
对象实际上更像是一种数据结构,并且可能永远不会有任何与自身相关的真实行为。)
这有什么意义吗?我是否偏离 OOP 路径太远了?对我来说,这代表了在如此抽象以至于实现几乎不可能 (xAL) 与严格偏向美国之间的一种相当明智的折衷。
2 年后更新:我最终得到了一个与此类似的系统,并在我已停刊的博客上写了一篇关于它的文章。
我觉得这个解决方案是遗留数据和关系数据存储之间的正确平衡,至少对于电子商务世界来说是这样。