5

在过去的几个月里,我最近开始使用 Java 进行编码。我有一个 Matrix 类,它有很多方法,变得过于臃肿。我还有一个 SquareMatrix 类,它扩展了 Matrix,并减少了一些臃肿。

我发现 Matrix 类中的许多方法通常与矩阵相关。它具有所有基础知识,如 addMatrix(Matrix)、multiplyMatrix(Matrix)、multiplyMatrix(float),以及更复杂的方法,如 getGaussian(Matrix) 或 getLUDecomposition(Matrix)。

在减少班级矩阵中的行数方面,我有哪些选择?一个类变得非常大是正常的吗?我不这么认为......这是我应该尽早考虑的事情并且重构很困难吗?还是有简单的解决方案?

谢谢!


编辑:在阅读了几个回复后,我正在考虑执行以下操作:

实用程序类Matrix 包含矩阵的所有常用/基本方法

委托类(Helper/sub):

*助手类* getGaussian(..), getLUFactorization(..), ...

子类 (扩展矩阵)SquareMatrix、LowerTriMatrix、UpperTriMatrix、...

委派似乎类似于在 C++ 中定义多个带有标头的 .cpp 文件。仍然欢迎更多提示。


Edit2:另外,我更喜欢通过正确设计来重构,而不是快速修复。我希望它对未来的项目有所帮助,而不仅仅是这个。

4

5 回答 5

3

接口应该是完整的和最小的,这意味着一个类型接口应该包含在该类型上实现所需和有意义的任务所必需的所有方法,并且只有这些。

因此,分析 Matrix 的 API 方法并确定它们中的哪些属于核心 API(必须有权访问类的内部才能完成其任务),哪些提供“扩展”功能。然后将类 API 简化为核心功能,将其余方法迁移到单独的帮助程序/实用程序/子类,这些子类可以使用公共核心 API 完成其目标。

如需重构/单元测试帮助,请考虑获取Michael Feathers 的《有效使用遗留代码》 。

于 2012-04-18T08:49:05.207 回答
2

重构绝对是一件好事,但除非你有好的单元测试,否则很难可靠地重构。测试驱动开发提供了一种实现通常易于重构的代码库的方法。

对于没有单元测试的现有代码,这意味着在你需要首先隔离要重构的区域之前,先编写单元测试,然后再重构。但是,如果这只是一个个人项目,您可能可以通过编写测试来避免您希望在重构中完好无损地生存的最小功能集。

关于如何进行手头的重构,有一些原则和方法,就像其他一些答案已经指出的那样。在大多数情况下对我有用的是:

严格执行以下样式规则:

  1. 方法不能超过 40 行
  2. 类扇出不能超过 20

还有其他的,但我个人发现这些对引导自己远离糟糕的设计最有帮助。限制方法长度迫使您真正考虑方法签名并编写简洁、重点突出的方法。这通常使重复更容易发现和删除。限制类扇出在类层面也有类似的效果,它迫使你认真思考类的角色并使其简洁。

诸如此类的工具checkstyle可以强制执行这两者,以及许多其他样式规则。

EclipseIDEA IntelliJ都提供了“提取方法”重构,这使得它就像突出显示要提取的代码并点击快捷键一样简单。IntelliJ 甚至会检查类中是否出现完全相同的代码,并将它们替换为对新方法的调用。事实上,我建议一直使用这样的重构工具,而不是手动复制粘贴和编辑。

于 2012-04-18T09:13:56.537 回答
2

让你臃肿的班级看起来干净的快速而肮脏的方法(通过将烂摊子移到别处)

您可以将方法的内容放在外部实用程序类的静态方法中。

例子:

矩阵.java

import MatrixUtils;
//[...]
public class Matrix
{
    //[...]
    Matrix()
    {
        //[...]
    }
    //[...]
    public Gaussian getGaussian(Matrix m)
    {
        return MatrixUtils.computeGaussian(m);
    }
    public LUDecomposition getLUDecomposition(Matrix m)
    {
        return MatrixUtils.computeLUDecomposition(m);
    }
}

MatrixUtils.java

protected class MatrixUtils
{
    private MatrixUtils()//Utility class: prevent instantiation
    {//nothing
    }
    //[...]
    protected static Gaussian computeGaussian(Matrix m)
    {
        //do your superlong 100+lines Algorithm and return the result
    }
    public static LUDecomposition computeLUDecomposition(Matrix m)
    {
        //do your superlong 100+lines Algorithm and return the result
    }
}

通过这种方式(如我所说,又快又脏),您可以干净地浏览 Matrix 类(尤其是当您有很多方法和 javadoc 时)。

当您想访问实际代码时,您可以使用 MatrixUtils。

如果由于某种原因,每个方法都超长(超过 200 行代码!?)并且如果出于其他原因,您确实需要保持 .java 文件简短,您甚至可以创建一个“静态类” "(即仅具有静态方法的实用程序类)适用于每个 [uber-long] 方法。

...当然,在任何情况下,您都应该在某种程度上进行“程序”重构,正如@oksayt 所提到的,您可以通过将一些代码块放入单独的(但连贯的)函数中来缩短方法。

于 2012-04-18T09:17:17.773 回答
1

“非常大”是什么意思?

我认为该方法不应超过 100 行,类不应超过 1000 行,包括 javadoc。如果您需要更多,请检查您的设计。使用委托,即将你的逻辑分成模块/类,并从另一个类中调用一个类。

于 2012-04-18T08:50:34.260 回答
0

对于基本的矩阵运算,您可以使用具有合适许可证的开源实现。你可以考虑:-

http://math.nist.gov/javanumerics/jama/

http://code.google.com/p/efficient-java-matrix-library/

http://commons.apache.org/math/

这肯定会减少您的整体代码大小,并且您会从更多经过测试、使用过的代码库中受益。

希望这可以帮助。

于 2012-04-18T09:19:13.447 回答