9

I have a project where I have two classes that both require a database access object that updates the same table. The constraints of the framework and project make it so that I cannot combine these two classes. I have created a case below that shows how the setup is. Class A needs to be able to update and read the record, while class B needs to be able to update and delete the record.

If I use the classes as they are, it works just fine, but I am having a problem with that fact that each of the classes is requiring functionality that it is not using to be implemented. For example, in order to use class A, I have to pass it a dao that implements the delete function, even though it will never be called. Similarly, I have to pass class B a dao that implements the read function but it will never be called.

I thought about approaching it by having interfaces that inherit others (IReadDao, IUpdateDao, IDeleteDao being the daos that would be inherited from), but this approach would basically require a different interface for each combination of functions (IUpdateAndRead, IReadAndDelete, IReadAndUpdate ...)

I want to use an interface for the dao because I don't want to couple the application with the database. Is there a pattern or method for accomplishing what I want that anybody knows about? Thanks in advance.

class IDao {

  void update(ModelDao model);
  void delete(String guid);
  ModelDao read(String guid);

}

Class A {

  private IDao dao;

  public A(IDao dao) {

    this.dao = dao;

  }

  public void doStuff() {

    ModelDao model = new ModelDao();

    ...

    dao.update(model);

  }

  public void readThenDoSomething(String id) {

    ModelDao model = dao.read(id);

    ...

  }

}

Class B {

  private IDao dao;

  public B(IDao dao) {

    this.dao = dao;

  }

  public void makeUpdate() {

    ModelDao model = new ModelDao();

    ...

    dao.update(model);

  }

  public void delete(String id) {

    dao.delete(id);

  }

}
  • 2
    Why do you need separate interfaces for each combination as opposed to just having each class that uses them implement the ones they need? – yitzih Feb 20 '17 at 20:10
  • In the case above, rather than pass IDao to the constructor of A, I would have to pass an object that implements IUpdate and IRead, so what would the type of the instance variable "dao" be? Wouldn't it have to be something like IUpdateAndReadDao? It still needs to be an interface because if I tell it to take an implementation that is database specific I have coupled the class to the db. Is that what you were asking? – jteezy14 Feb 20 '17 at 20:18
  • 3
    I think this is a perfect example of Interface Segregation Principle (the I from SOLID). Might want to read a bit on it. – Christopher Francisco Feb 20 '17 at 20:49
10

Per Christopher's comment, it is probably slightly better to segregate the interfaces. So you would need at least IReadDao, IDeleteDao, and IUpdateDao. Note that you don't necessarily need three classes; you can have one big DAO class that implements all three interfaces, if it makes sense for the code base to be combined in that manner.

To avoid combinatorial explosion (e.g. to avoid the need for a IReadUpdate, IDeleteUpdate, etc. interface) you can provide the interfaces separately in constructor injection (you can pass the same object twice as different parameters), or provide a single object supporting two or more interfaces in a generic method call using extends.

Constructor injection:

class MyDaoLibrary : IUpdateDao, IInsertDao, IDeleteDao {
    //Etc....
}

class A
{
    //It is OK if the IoC container factory provides the same instance for both parameters.
    a(IUpdateDao dao1, IDeleteDao dao2) {
        this.updater = dao1;
        this.deleter = dao2;
    }
    //Etc....
}

Setter injection, using generic method:

<T extends IUpdateDao & IDeleteDao> void InitializeDao(T dao)  //Pass a single object that implements both IUpdateDao and IDeleteDao
  • When using setter injection, how would I declare the instance variable that I am setting in the InitializeDao function? – jteezy14 Feb 20 '17 at 22:21
  • You would need two instance variables (one for deletes, one for updates)... assign dao to both. – John Wu Feb 20 '17 at 22:22
  • Oh yes, that makes sense. Thanks very much for the great answer! – jteezy14 Feb 20 '17 at 22:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.