4
public interface iUserInfo
{
    string getUserName(int userId);
    string getUserAge(string username);
}

public class UserDb implements iUserInfo
{
    string getUserName(int userId)
    {
        //code to retrieve user info from the database
    }
}

public class UserTxtFile implements iUserInfo
{
    string getUserName(int userId)
    {
        //code to retrieve user info from the plain text file
    }
}

public class UserManager()
{
    private iUserInfo userInfo;

    public string retrieveUserData(string userName)
    {
        return userInfo.getUserAge(userName);
    }
}

My professor says

"the above user manager class has a reference variable of type iUserInfo, so, if this reference is provided by a factory method or by any other means, the code of the manager class will be the same regardless of what implementation is provided.

This approach maximizes flexibilty if some implementations need to be altered during the process of software development, as higher level layers will not be affected at all."

There are two things I need to understand; the flexibility maximization and the factory method.

The latter I guess it may be something like this

public class UserManager()
{
    private iUserInfo userInfo;
    private UserTxtFile  uTxtFile;
    private UserDb uDB;
    public iUserInfo GetUserInfoObjFactory(bool dbOrTxt)
    {
        return dbOrTxt? uTxtFile:uDB;
    }
    public string retrieveUserData(string userName)
    {
        return userInfo.getUserAge(userName);
    }
}

and during the lecture I was sort of daydreaming about other things, and now can't figure out what that exactly means ? I would love to understand a little more in depth, just in case some interviewers may attack me with more open questions that I am unsure of how to answer.

Could you also add some code that will break the above source in an example case when the high level layers are affected ? Thank you a lot.

[Update] I also find an answer such as "we need Interface to group common methods" is not really convincing. An Abstract base class alone does help too. For example, a Fly behavior from 2 objects {Penguin vs Bird}. I can't simply tell the interviewer that IFly is needed at all. Even when I have millions of different objects which need Fly, then I can always implement each Fly for each of them. Because I still need to do that in the implementing classes even when I design the IFly. Would you please offer more detail cases or re-explain how interface becomes a must ?

Luiggi Mendoza
  • 85,076
  • 16
  • 154
  • 332

3 Answers3

1

About the need for interfaces.

Let's assume that you have to implement airport dispatcher. It interacts with object in airport space, giving them commands with regard to their position and air situation. This set of commands is well-defined and it does not (should not) depend on the type of object in space. Dispatcher needs to know position, he must be able to allow landing, deny landing, delay landing and issue emergency course correction. For this to be implemented and maintained as easily as it's possible, we define a kind of interface which we implement in all "aircrafts".

Then we can create an AirportDispatcher, which will work with set of objects implementing our interface in generic way, without knowing how it is implemented (helicopters can wait in place, but airplanes need to go around while waiting) or even type of aircraft. All you should know is that it flies and it can obey your commands.

Please note that it is not an interface in terms of Java, it is just a contract, how we implement it depends only on language possibilities. Dynamic or duck-typed languages can do that without any syntactic constraints, while static typed languages will need some additional work.

There come interfaces and abstract classes. The major difference between interface and abstract class it that there may be several interfaces for one object, but only one abstract class (that is not how it goes in all languages, but that's common denominator). Also interface can not contain implementation while abstract class can.

casablanca
  • 69,683
  • 7
  • 133
  • 150
Sergei Rogovtcev
  • 5,804
  • 2
  • 22
  • 35
1

I will change your code a little bit in order to explain

Why Flexibility ?

Here is a piece of code in your system which will print the user name. What's more, let's image there are not just one, but hundred pieces of codes using UserDb directly, and they spread in your system everywhere.

public void printUserName(String userId) {
  UserDb db = getUserDb();
  System.out.println(db.getUserName(userId));
}

Now, what if we want to retrieve user information from text file ? The only way to do this, is to change all the code that use UserDb into UserTextFile. It is going to take lots of time, and it can introduce bugs easily because we can accidentally change something which we shouldn't.

We call these codes and UserDb are Coupling.

So here we have UserManager to solve this problem

public class UserManager {

  private UserDb db;

  public UserManager(UserDb db) {
    this db = db;
  }

  public String getUserName(String userId) {
    // return user name using UserDb
  }
}

If all codes in our system using UserManager as the way to retrieve user name. When we want to switch to text file, all we can do is change code inside UserManager.

But, in real world coding, UserManager cannot be that simple, they might also has other responsibility, such as validating input before query. We might still introduce bugs.

That's why we need another layer to remove this coupling once for all.

Here's an Interface

public interface iUserInfo {    
  public String getUserName(int userId);
  public String getUserAge(string username);
}

... and we make UserManager depend on iUserInfo

public class UserManager {

  private iUserInfo info;

  public UserManager(iUserInfo info) {
    this info = info;
  }

  public String getUserName(String userId) {
    // return user name using info
  }
}

Now, whenever we want to change UserDb into UserTextFile, all we do is writing a new concrete class of iUserInfo. UserManager will never notice, because it dose not need to know details of implementation.

The less code we modified, the less chance we introduce bugs. That's the reason we want such flexibility.

This technique is called Inversion of Control.


Factory method ?

Factory method is one of the design pattern that deal with object creation. Check this question for more information

Factory, Abstract Factory and Factory Method

The reason your profession mentioned factory method, is because these pattern are use to hide the creation knowledge of objects, iUserInfo in this case, from other class, that means these method/class are the only code coupled with concrete class.

So we can minimize the impact of changing implementation of iUserInfo

Interface v.s. Abstract Class ?

Interface make all of your concrete class works without extends it. This is good because in Java, you can only inherit from one class.

On the other hand, abstract class makes you easier to deal with common code that used between different implementation.

You can check this question for more detail Interface vs Base class

Community
  • 1
  • 1
Rangi Lin
  • 9,303
  • 6
  • 45
  • 71
  • I upvoted this mainly for one sentence: "UserManager will never notice, because it does not need to know details of implementation". I found this to be very important to understand the use for interfaces; A clear seperation between something's interface and something's implementation, can be used to make parts of a program only dependable on the interface, wich promotes loose coupling, which makes less changes necessary when refactoring. And less change equals less time, :-) – Tom Aug 05 '12 at 09:50
0

Your professor lecture means about loose coupling and the example refers to Bridge PAttern.

More detail:

The UserManager class must handle the data applying business logic and rules, save and retrieve it. This class must only know that it must save and retrieve the data to and from some place, but its not its responsibility to do the dirty work. Instead, you will have an object, the iUserInfo instance, that will handle the save and retrieve of the data. How will this object do this job? It doesn't concern for the UserManager class. This is loose coupling.

Now, why must be an interface/abstract class who handles this job? Because you could have different data sources: text files, xml files, relational database, in-memory data base, an external device, and so on. Your UserManager class must not directly call the data source handler, instead another class will provide this exact implementation. For this case, you must use an abstraction, that is handled by an abstract class or an interface. The abstract class and the interface is a contract that establishes the methods the client can use, but not necessarily the methods implementation. How this work? Let's check an example:

public interface iUserInfo {
    //the client (any class that uses the interface) knows that can get the UserName
    //and the UserAge, it doesn't need to know how...
    string getUserName(int userId);
    string getUserAge(string username);
}

public class UserDb implements iUserInfo
{
    string getUserName(int userId)
    {
        //this implementation will connect to database to get the data
    }
}

public class UserTxtFile implements iUserInfo
{
    string getUserName(int userId)
    {
        //this implementation will read from a text file to get the data
    }
}

By now, the UserDb and UserTxtFile classes will handle the dirty work. Now, your UserManager can take a breath because it must not know where the data will be stored. But there is another question: which implementation should UserManager use to get the data?

The factory method is an implementation of the Factory Method Pattern, that states the client must not know which implementation should it use, instead the Factory will take the decision, based in configurations or another business rules. This means, the UserManager class can rest in peace because it doesn't have to define the access neither the implementation! Sounds good right? Now, for the example, there is just a simple method that acts as the factory method

//it will return the iUserInfo implementation based in a boolean variable
//this could become more complex depending on the rules, like retrieving the boolean
//value from a configuration file
public iUserInfo GetUserInfoObjFactory(bool dbOrTxt)
{
    return dbOrTxt? uTxtFile:uDB;
}

More info:

Luiggi Mendoza
  • 85,076
  • 16
  • 154
  • 332