3

It's preferable to write programs that depend on interfaces rather than on superclasses, but what if you want a class to have certain variables? Sometimes you want a class to implement a certain variable. (For example, imagine you have a datasource interface, and want all classes to implement a "String user").

In this case, I can see making an abstract class "datasource", which other classes could then extend. But this means they can't extend another class anymore, due to no multiple inheritance in Java.

So, to conclude, if I would have the above scenario, should I rethink my design, or is there a pattern I don't know about that I could follow to achieve the interface-with-variable design?

Tulains Córdova
  • 39,201
  • 12
  • 97
  • 154
Dylan Meeus
  • 685
  • 1
  • 5
  • 18
  • 4
    Why do you need a field (which other best practices dictate shouldn't be public to begin with) rather than a getter/setter? –  Oct 22 '14 at 19:56
  • 1
    I could put in the interface 'public void setUser()', but than the actual implementation can still do pretty much whatever it wants. The classes that implement the interface NEED the String. I'm not sure where I said the field should be public? It can be private to each class still, I just need to know the classes that implement a certain interface also have a certain variable. (what they do with it can be different) – Dylan Meeus Oct 22 '14 at 20:04
  • [replace inheritance by delegation](http://programmers.stackexchange.com/a/241584/31260 "as reasoned here for has-a relationship")? "...This approach is so common, there is even an Eclipse refactoring exactly for this purpose" – gnat Oct 22 '14 at 20:13
  • If you inherit state from interfaces, it sounds like you could easily run into a [shared inherited state](http://stackoverflow.com/a/26339439/3496273) problem – Jack Oct 22 '14 at 21:05
  • 3
    Don't rethink your design, rethink your programming language. Depending on your situation, traits/mixins for example could be a good solution. Also, implements is not per se better than extends! It's two different tools for two different problems. – valenterry Oct 23 '14 at 07:10
  • @DylanMeeus Sounds like you're using some reflection-based magic that managed to turn private fields into public interface. Maybe your reflection needs to be more flexible. – Sebastian Redl Oct 23 '14 at 16:38
  • possible duplicate of [How to refactor my design, if it seems to require multiple inheritance?](http://programmers.stackexchange.com/questions/241582/how-to-refactor-my-design-if-it-seems-to-require-multiple-inheritance) – gnat Nov 11 '14 at 19:48

4 Answers4

9

If you need to share implementation, then use inheritance. That's what it's for. But use an interface as well, and treat the fact that inheritance is being used by the implementations as an implementation detail: client code shouldn't need to know.

For instance, see the library classes List, AbstractList, ArrayList and LinkedList. There are common implementation details of the two concrete classes which are shared by them both inheriting from AbstractList. But as a client of them, this is an unnecessary detail which we don't ever use... we only care that they both implement the interface, List.

Periata Breatta
  • 962
  • 4
  • 8
7

The premise of this question is a bit confusing. You cannot "implement a variable". It either exists or it doesn't. Further, "wanting" a class to contain a variable either means:

  • You own the code, so just put the variable in each of the implementing classes (via base class if so desired).
  • You don't own the code (future implementations of this interface). You can't dictate their implementation, only the specification, so don't worry about what they might name their user variable.

Beyond that, your options are limited by language. In C#, your interface could contain a property public String User { get; set; }. In Java, you are limited to using a base class, or possibly considering Java 8's default methods in interfaces.

Dan1701
  • 3,118
  • 1
  • 15
  • 24
3

You can add the following to the interface:

public void setUser(String s);
public String getUser();

That way implementors are kind of forced to have a username variable in their state. Although implementors may name it whatever they like.

That way you continue simulating multiple-inheritance through interfaces.

Any class extending another one that implements the interface can access the variable with super.getUser(); or you can even make the state variable protected, but that's an implementation detail.

Tulains Córdova
  • 39,201
  • 12
  • 97
  • 154
0

The very fact of asking whether you need to rethink your design indicates that you need to rethink it.

Result of your rethinking should be that you either (1) redesign the code so that it follows general practice for objects to expose behavior, not data, or (2) identify it as exceptional case where deviation of general norm is clearly justified (eg Data Transfer Object).


Technical way to make field usage enforced by interface is explained in this answer to prior question:

...Here you find a detailed example how to replace inheritance by delegation. This approach is so common, there is even an Eclipse refactoring exactly for this purpose

Applied to your case, above approach could look as follows.

First, you create a class (plain class, nothing special) with desired field(s):

public class Data {
    private String user;
    public void setUser(String user) { this.user = user; }
    public String getUser() { return user; }
}

Next, you define the interface that allows to delegate to above class:

public interface DataSource {
    public Data delegate();
    //... other methods here
}

As a result, any object implementing DataSource interface will be also forced to provide Data functionality to work with user String.

Worth reminding once again that you better do so only if this is clearly justified - besides already mentioned issue of exposing data instead of behavior, this also goes against the Law Of Demeter.

gnat
  • 21,442
  • 29
  • 112
  • 288