Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Simple Factory with constructors using different parameters

I have two ways of saving data in my application: save to database and save to file. Since I don't want client code dealing with construction of objects I created a class that (to my understanding) is simple factory with a factory method. Code below:

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

With this setup client code doesn't have to deal with constructing anything or deciding whether to save to DB or file - it can just call a save() method on an object returned by the factory like so:

DataPersister dataPersister = DataPersisterSimpleFactory.createDataPersister(this.savetoDb, this.session, this.filename);
dataPersister.save(this.data);

My question is - is this solution breaking SOLID principles? In order to create e.g. a DatabaseDataPersister client code needs to pass on a filename parameter, and this implementation of DataPersister won't have any use of it. I feel like it doesn't sit right with something similar to Interface-segregation principle but not quite that.

And if the solution is indeed a code smell - how do I go about cleaning it?

like image 842
naru Avatar asked Apr 20 '18 14:04

naru


1 Answers

The SOLID principle I think is in violation is DIP.

Your client classes, by having to depend on the static factory directly, have a compile-time dependency on actual implementations, DatabaseDataPersister and FileDataPersister, rather than just the abstraction DataPersister.

To solve, supply to the client the DataPersister you want them to use. The constructor is usually a good place for this:

public class ExampleClient {

    private final DataPersister dataPersister;

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

    public void methodThatUsesSave(){
        dataPersister.save(data);
    }
}

This code compiles without the concrete implementations, i.e. it has no dependency on them. The client also doesn't need to know the filename or session so it solves that code smell too.

We can decide which concrete implementation to give it at construction time, here I use your existing method:

DataPersister dataPersister = DataPersisterSimpleFactory.createDataPersister(this.savetoDb, this.session, this.filename);
ExampleClient example = new ExampleClient(dataPersister);
like image 70
weston Avatar answered Oct 21 '22 01:10

weston