如何在组件不断增加的情况下保持复合图案的效率



我目前正在用C#编写一些代码,并一度决定,对于我的特定情况,复合模式将非常有用。

然而,一旦我开始制作多个组件的组合,我的代码中显然存在性能问题。

我有点难以解释自己,所以这里有一些简单的代码会有所帮助。

class Interface IComponent
{
public double operation(double[] vector);
}
class Sum: IComponent
{
public double operation(double[] vector) 
{
double sum = 0;
foreach(double dub in vector) sum += dub;
return sum;
}
}
class SquaredSum: IComponent
{
public double operation(double[] vector) 
{
double sum = 0;
foreach(double dub in vector) sum += dub * dub;
return sum;
}
}
class Composite: IComponent
{
IComponent[] components;
public Composite(params IComponent[] components) this.components = components;

public double operation(double[] vector)
{
double sum = 0;
foreach(var component in components) sum += component.operation(vector);
return sum;
}
}

现在,如果我制作一个新的Sum和SquaredSum的复合对象,代码将不得不在双数组(向量(中循环两次,一次用于Sum实例,另一次用于SquaedSum实例。当我查看一百万行数据时,这是一个严重的问题。

理想情况下,我希望我的代码编译/操作大致类似于在同一个循环中计算总和和平方和。所以我只需要循环通过向量一次。

我的解决方案

我能想到的解决方案是将IComponent更改为一个抽象类,如下所示。

abstract class Component
{
public abstract double TransformData(dub);
public double operation(double[] vector)
{
sum = 0;
foreach(double dub in vector) sum += TransformData(dub);
return sum;
}
}
class Composite: Component
{
Component[] components;
public Composite(params Component[] components) this.components = components;

public double operation(double[] vector)
{
double sum = 0;
foreach(double dub in vector)
{
foreach(var component in components) sum += component.TransformData(dub);
}
return sum;
}
}

这将允许代码只对输入数组进行一次迭代。

我对解决方案的担忧是,每个组件的实现都会相当抽象。此外,每个组件仅限于对当前double/传递到其中的对象进行操作(也许我想要对下一个和上一个元素进行操作(。

例如,在我的解决方案中,实现一个计算平均值的组件是不可能的,这不是我想要的。

问题

我的问题是,有没有另一种神奇的OOP子弹可以有效地解决这个问题?

我部分知道LinQ可能提供了一个很好的解决方案,但我不知道如何。

谢谢。

您的解决方案对我来说意义不大。主要问题是您的IComponent对象无法轻松组合。以现实世界中的一些问题为例,比如计算标准偏差,我如何只使用IComponents来实现这一点?

我承认,构建这样一个解决方案是绝对可能的,但它可能相当复杂。

此外,您对性能的担忧似乎放错地方了。计算机是快速的,对于绝大多数代码来说,性能根本不重要。性能非常重要的主要情况是在处理大量数据时,如图像、视频等,其中有10^6+项需要处理。对于这些情况,典型的方法是在相当低的级别上进行编程,即在简单的数据结构(如数组(上进行简单的算术运算的普通循环。并且尽可能避免分支和不可内联的方法调用(即任何类型的polymorhpism(。一些代码越优化,它通常就越不抽象和可读。高度优化的代码往往是不可读的,或者由比代码多得多的注释组成。

因此,在您真正发现一个真正的性能问题之前,请担心可读性,而不是效率。

对于上面的任务,只做似乎要简单得多,可读性也更强

vector.Sum(v => v * v + v);

相关内容

  • 没有找到相关文章

最新更新