我将使用术语“盒子模型”泛指任何旨在表示“矩形容器”(又名“盒子”)的图形布局并执行相关计算(例如计算单个盒子的位置)的数据模型。调整封闭框的大小)。(这是这种模型的一个示例。)
我的问题的本质是:
我正在寻找具有以下属性的“盒子模型”的实现,大致按重要性排序:
- 它应该在布局信息的建模(例如尺寸、边距、填充、包含关系等)与在某些特定设备(例如 Web 浏览器、PostScript、X11 等)中呈现此信息之间保持清晰的分离;
- 它应该忠实地实现一些“标准”盒子模型(例如,w3's),或者,至少有足够大的采用基础来成为“事实上的标准”标题的可靠候选者;
- 最好用 Python 编写(第二选择:JavaScript;第三选择:其他任何东西!)。
我意识到,如果有什么东西可以满足这些标准,那么它不太可能是孤立的。它很可能是一个更大系统的一个组成部分。还行吧。
注意:IMO,这篇文章的其余部分不包含回答上述问题所需的任何信息。 我包含这些附加内容只是为了让那些可能想在回答之前知道这个问题来自哪里的人受益。 然而,它并不打算作为讨论的素材。请将对此的任何回复限制在评论部分。无论如何,如果与我的估计相反,此补充内容被认为不适合 SO,请告诉我,我将非常乐意将其删除。
这个问题背后的动机的一个简洁(虽然可能有点不透明)的陈述是这样的:
最大限度地减少我目前正在实施的图书馆添加的“认知失调”的数量。
更详细地说,我所指的“认知失调”是由每一个新软件引入的,这些软件以与任何其他现有的“基本等效但不相同”的方式对已确立的问题域进行建模在同一问题域中运行的软件。这种“认知失调”包括既定概念的新术语,或既定术语的新含义、新惯例等。
尽量减少这种认知失调的明显方法是坚持采用某些预先存在的标准数据模型的术语和约定的原则。当然,这种策略只有在有这样一个标准的数据模型的情况下才能成功,而且只有与它的流行程度成正比。(至少根据我的经验,被广泛采用的数据模型相对较少,这就是为什么我的目标只是“最小化”,而不是完全“避免”由我的图书馆造成的认知失调。)
更具体地说,我正在开发一个小型内部库,以解决对布局信息进行抽象编码和计算的问题。
这个库仍然非常简单,但我已经发现自己不得不在命名、约定和整体结构方面做出很大程度的任意选择。例如,在 Python 中:
# EXAMPLE 1
from __future__ import division
class Box(object):
def __init__(self, width, height):
self.width = width
self.height = height
def make_box(width, height, aspect_ratio=None):
if aspect_ratio is not None:
w = height * aspect_ratio
if w < width:
width = w
else:
height = width / aspect_ratio
return Box(width, height)
此函数创建最大的Box
对象,该对象将适合具有指定宽度和高度的周围框,并且将具有纵横比aspect_ratio
(如果指定)。
(注意:本文中的所有代码仅用于说明,而不是作为生产级代码的示例。因此:没有错误检查,没有性能优化,没有处理舍入错误等)
需要注意的一点是,即使在这个小玩具示例中,我已经介绍了几个可能符合或可能不符合“标准实践”的术语和约定,包括:
- 术语“box”、“width”、“height”和“aspect_ratio”的选择(与“frame”、“delta_x”、“delta_y”和“proportion”相对);
- 将“纵横比”定义为比率
width/height
(与比率相反height/width
); - 表达式中“宽度”和“高度”的“默认排序”
Box(50, 100)
; - 处理指定
aspect_ratio
和指定组合width
andheight
不同意的情况的策略(即:将width
and解释height
为maximal,而不是例如minimum、允许值)。
可以说,问题不仅限于术语或简单的约定,例如参数的默认顺序,还延伸到同样是约定问题的设计决策,即使它们具有更广泛的范围。
为了说明这一点,想象用一个Padding
类增强模型,并更改make_box
函数,以便返回一个Box
可能小于width
andheight
参数指定的大小的对象,它总是返回一个Box
具有这些尺寸的对象,但还包括一个属性编码指定的 和 指定的和padding
之间的任何差异。此外,当存在这样的差异时,在盒子的两侧平均分配剩余的空间(即使生成的填充对称)。(有关此描述的代码再现,请参见下文。)aspect_ratio
width
height
EXAMPLE 2
这个小的增强本身引入了另一组术语和约定,但我想关注这样一个事实,即这个小的增强已经指向模型的详细说明,包括一种额外类型的对象(“填充”),并且随之而来的是这种新型对象与预先存在的对象(特别是“盒子”)之间的特定(尽管很大程度上是任意的)关系。换句话说,这个小的增强实际上意味着模型的扩展,它会影响到库的其余部分,全局。我希望我的库也符合这种“全局”结构约定,而不仅仅是较小范围的约定,例如默认排序等。
当然,其中一些设计决策恰好与任何可能被视为“标准”的事物完全一致或足够接近。此外,每一个偏离这个标准的人都只会给潜在用户带来很小的认知负担。毕竟,如果标准术语不是“框”而是“框架”,那么对于那些阅读我的图书馆(最终)文档的人来说,在精神上用“框架”代替“框”的每一个提及都不会造成太大的负担。尽管如此,总的来说,特别是在已经包含许多其他类似库(并且典型的程序员必须使用)的“认知宇宙”中,每个库都添加了自己与约定的微小偏差,效果确实变得繁琐。这些不断变化的惯例阻碍了对新软件的学习,其中一个特别明显的表现形式是错误的形式,其中一些可能很难发现。
正如我已经说过的,希望一个人能够消除所有这些认知失调是不现实的。一方面,没有标准。最好的希望是混淆最少数量的用户,但即便如此,这个数字仍然很大。此外,在某些情况下,有意识地采用一些非标准约定或术语的长期利益(与程序员的短期便利相反)确实合理地证明了额外的认知失调。也就是说,我怀疑这样的案例相当罕见。
# EXAMPLE 2
from __future__ import division
class Padding(object):
def __init__(self, top=0, right=0, bottom=0, left=0):
self.top = top
self.right = right
self.bottom = bottom
self.left = left
class Box(object):
def __init__(self, width, height, padding=Padding()):
self.width = width
self.height = height
self.padding = padding
def make_box(width, height, aspect_ratio=None):
if aspect_ratio is None:
return Box(width, height)
else:
w = height * aspect_ratio
if w < width:
p = (width - w)/2
padding = Padding(left=p, right=p)
else:
h = width / aspect_ratio
p = (height - h)/2
padding = Padding(top=p, bottom=p)
return Box(width, height, padding)