0

我在 OO 模式方面有很多东西要学习,这是我多年来遇到的一个问题。我最终会遇到我的课程的唯一目的是程序性的情况,基本上只是将一个程序包装在一个类中。这似乎不是正确的 OO 做事方式,我想知道是否有人对这个问题有足够的经验来帮助我以不同的方式考虑它。我在当前应用程序中的具体示例如下。

在我的应用程序中,我从工程测量设备中获取一组点并将它们标准化以在程序的其他地方使用。“规范化”是指整个数据集的一组转换,直到达到目标方向。

每个转换过程都将输入一个点数组(即形式为class point { float x; float y; float z; })并返回一个长度相同但值不同的数组。例如,像point[] RotateXY(point[] inList, float angle). 另一种过程是分析类型的,用于补充规范化过程并决定下一步要进行什么转换。这种类型的过程接受与参数相同的点,但返回不同类型的数据集。

我的问题是,在这种情况下使用什么好的模式?我要编写的代码是一个 Normalization 类,它继承了 RotationXY 的类类型。但是 RotationXY 的唯一目的是旋转点,所以它基本上是实现一个功能。但是,由于我在第一段中提到的原因,这似乎不太好。

提前致谢!

4

4 回答 4

3

在您的问题域中查找候选类的最常见/最自然的方法是查找名词,然后扫描与这些名词相关的动词/动作,以找到每个类应该实现的行为。虽然这通常是一个很好的建议,但这并不意味着您的对象只能代表具体元素。当流程(通常被建模为方法)开始增长并变得复杂时,最好将它们建模为对象。因此,如果您的转换本身具有权重,则可以将其建模为对象并执行以下操作:

class RotateXY
{
public function apply(point p)
{
//Apply the transformation
}
}

t = new RotateXY();
newPoint = t->apply(oldPoint);

如果您有许多转换,您可以创建一个多态层次结构,甚至可以将一个转换一个接一个地链接起来。如果您想更深入地挖掘,您还可以查看与此密切相关的命令设计模式。

最后的一些评论:

  • 如果适合您的情况,最好在点级别对转换进行建模,然后将其应用于点集合。这样你就可以正确地隔离转换概念,也更容易编写测试用例。如果需要,您以后甚至可以创建转换组合
  • 我通常不喜欢Utils具有一堆静态方法的(或类似的)类,因为在大多数情况下,这意味着您的模型缺少应该承载该行为的抽象。

高温高压

于 2012-11-20T12:00:01.093 回答
1

通常,当涉及到只包含静态方法的类时,我将它们命名为 Util,例如 DbUtil 用于外观 DB 访问,FileUtil 用于文件 I/O 等。因此,找到一个所有方法共有的术语并将其命名为 Util。也许在你的情况下 GeometryUtil 或类似的东西。

于 2012-11-19T23:46:32.877 回答
1

由于您应用的转换的细节似乎是针对问题的临时性的,并且将来可能容易更改,您可以将它们编码在配置文件中。

该点的客户端将从文件中读取并知道要做什么。至于旋转或任何其他变换方法,它们可以很好地作为 Point 类的一部分。

于 2012-11-19T23:51:13.150 回答
1

我认为只有一个成员的类/接口没有什么特别的问题。

在您的情况下,该成员是“具有返回相同类型的一种类型的某些参数的操作”-对于某些数学/功能问题很常见。您可能会发现拥有将多个转换类组合在一起以形成更复杂的转换的接口/基类和辅助方法很方便。

替代方法:如果您的语言支持它只是完全采用功能样式(类似于 C# 中的 LINQ)。

关于功能风格建议:我从以下基本功能开始(可能只是在该语言的标准库中找到它们)

  • collection = map(collection, perItemFunction)转换集合中的所有项目(Select在 C# 中)
  • item = reduce (collection, agregateFunction)将所有项目减少为单个实体(Aggregate在 C# 中)
  • 在 item 上结合 2 个功能funcOnItem = combine(funcFirst, funcSecond)。在 C# 中可以表示为 lambda Func<T,T> combined = x => second(first(x))
  • “绑定”/咖喱- 修复函数的参数之一functionOfOneArg = curry(funcOfArgs, fixedFirstArg)。可以在 C# 中表示为 lambda Func<T,T> curried = x => funcOfTwoArg(fixedFirstArg, x)

此列表将让您执行类似“将 X 轴上的集合中的所有点旋转 10 并将 Y 移动 15”之类的操作:map(points, combine(curry(rotateX, 10), curry(shiftY(15)))

语法将取决于语言。即在 JavaScript 中,您只需传递函数(并且 map/reduce 已经是语言的一部分),C# - lambda 和Func类(如参数函数 - Func<T,R>)是一种选择。在某些语言中,您必须明确使用类/接口来表示“函数”对象。

替代方法:如果您实际处理点和转换,另一种传统方法是使用 Matrix 表示所有线性运算(如果您的语言支持自定义运算符,您将获得看起来非常自然的代码)。

于 2012-11-19T23:52:01.333 回答