我有两节课。SpeciesReader
获取文件并解析它们。Species
存储有关物种的某些数据,这些数据已从文件中解析。
目前,我有一个方法:SpeciesReader.generateSpecies()
,它使用实例化它的文件来创建一个Species
对象。这是不好的做法/设计吗?我是否应该找到一种方法将其移至以Species
文件名作为参数的构造函数?
我有两节课。SpeciesReader
获取文件并解析它们。Species
存储有关物种的某些数据,这些数据已从文件中解析。
目前,我有一个方法:SpeciesReader.generateSpecies()
,它使用实例化它的文件来创建一个Species
对象。这是不好的做法/设计吗?我是否应该找到一种方法将其移至以Species
文件名作为参数的构造函数?
一点也不。这是一种称为工厂的常见模式。
话虽如此,工厂通常是在类本身(在这种情况下为 Species)而不是单独的类上实现的,但我认为这样分离它没有问题。
至于这个责任是否应该由物种代替,这取决于文件的性质。如果一个文件只包含一个 Species 并且在加载该文件时没有很大的开销,那么让它成为 Species 的一部分可能是有意义的。
但是如果文件包含很多物种或者初始化成本很高,那么将这个职责转移到另一个类并让它负责创建 Species 对象是非常有意义的。
你所拥有的是工厂方法模式的一个例子。这种创建模式在某些情况下可以很好地使用。然而,我个人的偏好是尝试将其使用限制为仅用于更易读的 ctor 替代品,而不是在其中做任何过于复杂的事情。这是为了简化依赖这个工厂的任何类的测试。
对于具有复杂结构的东西,我会使用Abstract Factory。通过这种方式,我可以测试依赖于所述工厂的组件,而无需创建一堆文件和工厂拥有的任何其他依赖项。
上面你问的是在工厂中有一个单例与一个静态方法。我对此的看法是:静态方法适用于可读的ctors,单例方法会激怒任何喜欢单元测试的人。
您可以使用几种模式:
选择实现哪种模式取决于用例,但 Cletus 是正确的,工厂似乎是一个不错的选择。
public class SpeciesFactory
{
private final static SpeciesFactory INSTANCE = new SpeciesFactory();
private SpeciesFactory() { }
public static SpeciesFactory getFactory()
{
return INSTANCE;
}
public Species getSpecies(String filename)
{
Species species = null;
//do business logic
return species;
}
}
您可以通过调用 Species carnivore = SpeciesFactory.getFactory().getSpecies("carnivore.txt"); 来使用它。
将文件的解析与从该文件解析的对象的实现分开是一个好主意。这被称为“关注点分离”。Species 的实现不应该知道或关心它在持久存储中是如何表示的(在 OO 设计术语中,它应该是“持久不可知论”)或传递给其构造函数的参数来自哪里。它应该只关心创建后如何与系统中的其他对象交互,但是创建是发生的。物种如何在持久存储中表示的问题应该在其他地方实现,在您的情况下是在 SpeciesReader 中。
将对象与其持久化的方式分开通常是更好的主意。想象一下,如果有很多方法可以加载Species - 从二进制文件、从 xml 文件、从数据库记录、从网络套接字等 - 可怜的 Species 不想知道程序的每个部分。