我应该说出一个唯一目的是程序性的课程?

时间:2012-11-19 23:34:22

标签: oop design-patterns 3d modeling

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

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

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

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

提前致谢!

4 个答案:

答案 0 :(得分:3)

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

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

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

如果你有很多转换,你可以创建一个多态的层次结构甚至链接一个接一个的转换。如果你想深入挖掘一下,你也可以看一下与此密切相关的Command设计模式。

一些最终评论:

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

HTH

答案 1 :(得分:1)

通常,当涉及仅包含静态方法的类时,我将它们命名为Util,例如用于表示数据库访问的DbUtil,用于文件I / O等的FileUtil。因此,找到所有方法都有共同点的术语,并将其命名为Util。也许在您的情况下GeometryUtil或其他类似的东西。

答案 2 :(得分:1)

由于您应用的转换细节似乎是针对该问题的特定内容,并且可能在将来容易发生更改,因此您可以在配置文件中对其进行编码。

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

答案 3 :(得分:1)

我认为没有特别错误的类/接口只有一个成员。

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

替代方法:如果你支持语言,那就完全是功能风格(类似于C#中的LINQ)。

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

  • collection = map(collection, perItemFunction)转换集合中的所有项目(C#中的Select
  • item = reduce (collection, agregateFunction)将所有项目缩减为单个实体(C#中的Aggregate
  • 合并项目funcOnItem = combine(funcFirst, funcSecond)上的2个功能。可以在C#Func<T,T> combined = x => second(first(x))中表示为lambda。
  • “bind”/ curry - 修复函数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来表示所有线性操作(如果您的语言支持自定义操作符,则可以获得非常自然的代码)。