带有使用不同参数的构造函数的 Java 简单工厂

nar*_*aru 6 java oop design-patterns factory solid-principles

我有两种在我的应用程序中保存数据的方法:保存到数据库和保存到文件。由于我不希望客户端代码处理对象的构造,因此我创建了一个类(据我所知)是带有工厂方法的简单工厂。代码如下:

public static DataPersister createDataPersister(Boolean saveToDb, Session session, String filename) {
    if (saveToDb) {
        return new DatabaseDataPersister(session);
    } else {
        return new FileDataPersister(filename);
    }
}
Run Code Online (Sandbox Code Playgroud)

使用此设置,客户端代码不必处理构建任何内容或决定是否保存到数据库或文件 - 它只需调用save()工厂返回的对象上的方法,如下所示:

DataPersister dataPersister = DataPersisterSimpleFactory.createDataPersister(this.savetoDb, this.session, this.filename);
dataPersister.save(this.data);
Run Code Online (Sandbox Code Playgroud)

我的问题是 - 这个解决方案是否违反了 SOLID 原则?例如,为了创建一个DatabaseDataPersister客户端代码需要传递一个filename参数,并且这个实现DataPersister不会使用它。我觉得它与类似于接口隔离原则的东西并不相符,但并非如此。

如果解决方案确实是代码异味 - 我该如何清理它?

wes*_*ton 3

我认为违反的SOLID原则是DIP。

您的客户端类必须直接依赖于静态工厂,因此在编译时依赖于实际实现,DatabaseDataPersisterFileDataPersister不仅仅是抽象DataPersister

要解决这个问题,请向客户提供DataPersister您希望他们使用的产品。构造函数通常是执行此操作的好地方:

public class ExampleClient {

    private final DataPersister dataPersister;

    public ExampleClient(DataPersister dataPersister) {
        this.dataPersister = dataPersister;
    }

    public void methodThatUsesSave(){
        dataPersister.save(data);
    }
}
Run Code Online (Sandbox Code Playgroud)

该代码无需具体实现即可编译,即它不依赖于它们。客户端也不需要知道filenameorsession所以它也解决了代码味道。

我们可以在构建时决定给予它哪种具体实现,这里我使用您现有的方法:

DataPersister dataPersister = DataPersisterSimpleFactory.createDataPersister(this.savetoDb, this.session, this.filename);
ExampleClient example = new ExampleClient(dataPersister);
Run Code Online (Sandbox Code Playgroud)

  • 我发现你的评论最有帮助。我可以根据命令行参数轻松注入正确的“DataPresister”。谢谢! (2认同)