Ghostkeeper
Ghostkeeper

Reputation: 3050

Java: Protected Method Before Interface

I have to design a datastructure that'll get implemented multiple times, and I've struck upon a problem.

Since my datastructure needs to have multiple versions of it, I've created an abstract class that lays the groundwork for all implementations. However, the datastructure requires a set-view of certain parts too.

The problem becomes as follows: The set needs to have different implementations depending on the implementation of my datastructure: Either the HashSet or the Collections.SingletonSet. The two implementing datastructures will then extend bits of these to do additional tasks when items are added or removed from the set. However, the abstract datastructure also requires a way to internally remove elements from this set such that this extra work isn't done. For this I'd like to add a protected method to the set, but I can't!

To illustrate, here's some sample code relating to the type of datastructure I'm creating:

public abstract class AbstractEdge {
    public abstract AbstractSetView destination(); //Gives a subclass of AbstractSetView in implementations.

    public void doStuff() {
        destination().removeInternal(foo);
    }

    public abstract class AbstractSetView implements Set<Vertex> {
        protected abstract void removeInternal(Vertex vert);
    }
}

public class Edge extends AbstractEdge {
    public SetView destination() {
        return new SetView();
    }

    public class SetView extends AbstractSetView,Collections.SingletonSet<Vertex> { //Doesn't work this way.
        protected void removeInternal(Vertex vert) {
            //Do stuff.
        }
    }
}

public class HyperEdge extends AbstractEdge {
    public SetView destination() {
        return new SetView();
    }

    public class SetView extends AbstractSetView,HashSet<Vertex> { //Doesn't work this way.
        protected void removeInternal(Vertex vert) {
            //Do stuff.
        }
    }
}

These are the options I've considered:

Surely the designers of Java made some way around this, to enable me to use their built-in Set implementations? What am I overlooking?

Upvotes: 3

Views: 248

Answers (2)

Veronica Cornejo
Veronica Cornejo

Reputation: 488

No, they did not "make some way around this" because they didn't see any obstacle, problem, or limitation. According to them, multiple inheritance was not really needed in the language because at least 85% of the time it is used when what really corresponds is composition. 14% of the remaining cases can be solved through interfaces and non-natural use of composition, and 1% with code replication. True: the later is U.G.L.Y. and R.E.D.U.N.D.A.N.T. and U.N.S.A.F.E., etc, but the main objective was to create a small language that could be implemented even in embedded devices. They were not going to give this up for just 1% of the cases. IMHO, they were about right in the percentages.

To answer your second question: don't inherit, especially from library classes, when what you really need is composition. Make AbstractEdge have a member protected Set backingSet; which is initialized with different Set implementations by the subclasses. This is implies that you don't need AbstractSetView and its subclasses.

Otherwise, member protected Set backingSet; can be located in AbstractSetView.

Upvotes: 2

Simone Gianni
Simone Gianni

Reputation: 11662

The two answers given so far both offer a solution and advice for the Set case. However, a pattern you can use in this and other similar situations (for example, you are not extending a JRE class, but your own stuff) is to split the interface in a public and an inner protected one.

Your public interface, in this case, will be Set.

Your protected inner interface will be InternalSet, declared inside AbstractEdge, defining the removeInternal method. The method will be "public", but the interface does not need to be.

Then, the abstract super class should define a public method returning the public interface for use outside your subclasses, and a protected one returning the protected interface for internal use only.

Implementing subclasses can then implement a class, extending whatever Set you need, and also implementing the protected class, and return an instance of it from both methods.

The choice between composition or inheriting from JRE classes is all yours.

Upvotes: 0

Related Questions