1

I have a Java question and I can't see how I can implement the methods correctly. I am not very good with architecture.

Data Manager interface class:

public interface DataManager {
   public void readData();
   public void writeData();
}

Data abstract class:

public abstract class Data implements DataManager {
    @Override
    public void readData() {};
    @Override
    public void writeData() {};
}

Data Reader class:

public class DataReader extends Data {
   // I want to implement the readData() here
}

Data Writer class:

public class DataWriter extends Data {
   // I want to implement the writeData() here
}

If I want to implement the readData() and writeData() separately in two different classes with only one interface, is it possible? I don't know why I am doing this way. Maybe it just looks cleaner and easier when I add more methods to the reader or writer class. Should I implement everything in just one single class?

I want this library to allow users using the manager object to have access for data reading and writing. But for implementation, I don't know how I can do it correctly.

Cao Felix
  • 329
  • 2
  • 6
  • 24
  • 4
    Any class that implements `DataManager` *must* implement both methods. You can have an empty implementation (like in your abstract class), but it would be better to split it into two interfaces if you intend for them to be implemented separately. – resueman Aug 08 '16 at 20:59
  • 3
    Alternatively to @resueman 's comment, you could do this with composition instead of inheritance. In that case, you would have a `DataManager` class that took `DataReader` and `DataWriter` classes as constructor arguments, and passed the implementation off to them. I think that might be close to what you're aiming for? – Edward Peters Aug 08 '16 at 21:04
  • @resueman thanks, so it sounds like I can either pick creating two interfaces or implement DataManager in one single class. – Cao Felix Aug 08 '16 at 21:05
  • @EdwardPeters thanks, I am not sure if I understand it. you mean like DataManager(DataReader reader, DataWriter writer)? So have readData() in DataReader and writeData() in DataWriter. Then manager will have the two objects so to use that calling the read and write methods. – Cao Felix Aug 08 '16 at 21:09
  • @CaoFelix The idea is that the `read` and `write` methods in the `DataManager` class would be very small "wrapper" methods for calls to the `DataReader` and `DataWriter` objects it was passed. This meant that if you had some set of different Writers and some set of different Readers, you could easily make a Manager out of any combination of them. – Edward Peters Aug 08 '16 at 21:12
  • @EdwardPeters Thanks – Cao Felix Aug 26 '16 at 16:34

4 Answers4

3

Looks like you've stumbled on the reason for the "Interface Segregation Principal". https://en.wikipedia.org/wiki/Interface_segregation_principle

While DataReader and DataWriter may seem related at first, and it might look like it makes sense to group them into your common interface DataManager, the job of reading and writing is quite different, and warrants a separation into two interfaces, e.g. IReader and IWriter.

Suppose you have a class that needs both a reader and a writer together, and so your DataManager interface makes sense. However, there's nothing stopping you from passing two objects, one of type IReader and one of type IWriter even if they're the same class underneath. But it seems you've already separated them into DataReader and DataWriter, which is good. As one of the other answers suggests, this is the application of the Single Responsibility Principal.

Erik Uggeldahl
  • 1,076
  • 11
  • 23
2

A best practice in programming is the "Single Responsibility Principle". A reader is not a writer, so it shouldn't be a subtype of a DataManager that requires its implementors to be both. By defining an abstract class that creates empty methods for the entire interface, you've also lost the value of having an interface. An interface is a contract that every implementor must /be-a/ case of its supertype. A reader is not a candidate to /be-a/ reader and a writer. You want a separate reader and writer interface, and have your readers implement one, writers the other, and datamanagers can implement both.

Also, don't use Reader and Writer in names for types that aren't subtypes of java.io.Reader and java.io.Writer, respectively. Since you're thinking of "data managers", maybe you could use ReadManager and WriteManager, or something like that, that lets people know you aren't using the standard Reader and Writer hierarchies.

Lew Bloch
  • 3,364
  • 1
  • 16
  • 10
  • I like that Single Responsibility Principle. I was reading http://stackoverflow.com/questions/10620022/example-of-single-responsibility-principle after you mention it. – Cao Felix Aug 08 '16 at 21:27
0

If you're only having a certain subclass implement each method, you don't need DataManager or Data. Just have DataReader and DataWriter contain only the methods they need, like so:

public class DataReader {
   public void readData() {...}
}
...
public class DataWriter {
   public void writeData() {...}
}

The whole reason of extending and implementing is to either clean up code, or allow for overriding another method. The way you're doing it does neither, so why not just keep it simple?

RobotKarel314
  • 417
  • 3
  • 14
  • I agree with you. Maybe this is not a very good code sample. What I am trying to do in my real application is to read some files (ie. CSV) and save the data into database. It will create tables and fill data into columns. Then I need to read data from the database and generate different files as well. So there will be reader for reading the files and database. And also there will be writer for writing data into database and generate files. The problem is, somehow my boss wants to have single object can call all the functionalities... – Cao Felix Aug 08 '16 at 21:23
  • Could you just make one class, then have it contain both methods, without any of the interface/abstract class stuff? – RobotKarel314 Aug 09 '16 at 11:10
  • Coding to the interface is good practice even in such simple situations. – Lew Bloch Aug 10 '16 at 17:46
0

After a lot of modification, so I do it this way and I think it fits my solution.

Data Manager interface class:

public interface DataManager {
   public Data readData(); // from database
   public void writeData(); // to database
}

DataConnector class:

public class DataConnector implements DataManager {
   DataCreate creator = new DataCreate();
   @Override
   public Data readData() {
       return creator.readData();
   };
   @Override
   public void writeData() {
       creator.writeData();
   };
   public Connection getConnection() {...};
   public void close() {...};
}

Data Create class:

public class DataCreate {
   public void readData() {
      new DataReader().readData();
   }

   public void writeData() {
      new DataWriter().writeData();
   }
}

Data Reader class:

public class DataReader {
   // I want to implement the readData() here
   public Data readData(){...};
}

Data Writer class:

public class DataWriter {
   // I want to implement the writeData() here
   public void writeData(){...};
}

Example:

DataManager manager = new DataConnector();
manager.readData();
manager.writeData();

So clients will only use methods from the manager public interfaces to do database reading and writing. Edward Peters mentioned composition to me and I did not understand it at that time. I am not very sure if what I am doing now is what composition should be doing. I think the credit should go to him. Thanks for the help.

Cao Felix
  • 329
  • 2
  • 6
  • 24