Private interfaces inside a class
Asked Answered
A

5

6

Here I came across this phrase:

Implementing a private interface is a way to force the definition of the methods in that interface without adding any type information (that is, without allowing any upcasting).

I'm finding it difficult to understand this. Can some one explain this for me?

Acaroid answered 20/12, 2014 at 11:40 Comment(2)
Possibly already answered here #4574213Salable
@Salable : I saw that question. But it doesn't clarify this phrase or I couldn't understand it. Could you please point me to a relevant section or a phrase?Acaroid
S
1

The examples in the linked article are a bit contrived and artificial (as already indicated by the odd names, A, B etc...). However, let's focus on the part of the quote that your question refers to:

"...without adding any type information (that is, without allowing any upcasting)."

The class may offer multiple (public or private) implementations of this interface. But the key point is:

Nobody will ever be able to figure out that they implement this interface.

Simply, because the interface is not public.

I tried to create an example showing a possible application case. Of course, it is still contrived, but may make the point more obvious. Consider you want to model a Tree data structure, which consists of Node objects. These can be InnerNode objects (which have child nodes) or LeafNode objects (which have no children).

Such a class could be implemented like this:

class Tree {

    // The private interface
    private interface Node {
        List<Node> getChildren();
    }      

    // Both are public implementations
    public class InnerNode implements Node {
        @Override 
        public List<Node> getChildren() {  
            return Arrays.<Node>asList(getLeafNode(), getLeafNode());
        }
    }
    public class LeafNode implements Node {
        @Override 
        public List<Node> getChildren() {  
            return Collections.emptyList();
        }
    }

    // These return the concrete, public types
    public InnerNode getInnerNode() { return new InnerNode(); }
    public LeafNode  getLeafNode()  { return new LeafNode();  }

    // This returns the private interface type
    public Node getRootNode() { 

        // Both concrete types can be returned here,
        // because they both implement the interface
        return getInnerNode(); // Works 
        //return getLeafNode(); // Works
    }

    // This uses only the interface type
    public void traverseNode(Node node) {
        System.out.println("Traversing "+node);
        for (Node child : node.getChildren()) {
            traverseNode(child);
        }
    }
}

In an external main method, you can observe the limitations imposed by the private interface:

public static void main(String[] args) {
    Tree tree = new Tree();

    // The public concrete types can be used
    Tree.LeafNode  leafNode  = tree.getLeafNode();
    Tree.InnerNode innerNode = tree.getInnerNode();

    // The private interface can not be used from outside:
    //Tree.Node node = tree.getRootNode();

    // This is possible: The class only uses its 
    // own private interface here
    tree.traverseNode(tree.getRootNode());
}

In this example, you can call traverseNode, passing in the Node that is returned by getRootNode, regardless of whether this node is a InnerNode or a LeafNode. In the current version, this will print something like

Traversing Tree$InnerNode
Traversing Tree$LeafNode
Traversing Tree$LeafNode

If you changed getRootNode to return a LeafNode, then it would only print

Traversing Tree$LeafNode

To put it simply, and as the name "private interface" already suggests: You can use this in order to hide the fact that two classes share a common ancestor.

Subset answered 20/12, 2014 at 12:41 Comment(0)
L
5

Here is an example of private interfaces.

public class Main  {

    private interface Animal {
        void makeNoise();
    }

    public static final class Cow implements Animal {
        @Override
        public void makeNoise() {
            System.out.println("Moo!");
        }
    }

    public static final class Sheep implements Animal {
        @Override
        public void makeNoise() {
            System.out.println("Bah!");
        }
    }

    public static void main(String[] args) {
        List<Animal> animals = Arrays.asList(new Cow(), new Sheep());
        for (Animal animal : animals)
            animal.makeNoise();
    }
}    

From within the class Main you can refer to an Animal and call makeNoise() on it. Therefore you can have a List of Animals of different types and use a for each loop to call makeNoise() on them all.

However, outside the class Main this is not possible. You can have a Cow or a Sheep and call makeNoise() on either, but the interface Animal and the interface method makeNoise() are invisible.

Lasting answered 20/12, 2014 at 12:27 Comment(4)
Thank you for your example. Although it is "hardly" used, the abstraction is quite powerful and this reduces the overall dependencies in the design and creates a potential for reuse.Acaroid
@Acaroid I've edited my answer. That last sentence (now deleted) was a matter of opinion.Lasting
Yeah..! Practically your opinion seems to be correct. But it is not logical to avoid using private interfaces. Opinions can be different, discussions are welcome. Thank You for your thoughts.Acaroid
FYI : I found out that this pattern is used extensively in an embedded real-time environment at Xerox. It is employed in order to break the thread of execution in classes that perform various services for their clients.Acaroid
S
1

The examples in the linked article are a bit contrived and artificial (as already indicated by the odd names, A, B etc...). However, let's focus on the part of the quote that your question refers to:

"...without adding any type information (that is, without allowing any upcasting)."

The class may offer multiple (public or private) implementations of this interface. But the key point is:

Nobody will ever be able to figure out that they implement this interface.

Simply, because the interface is not public.

I tried to create an example showing a possible application case. Of course, it is still contrived, but may make the point more obvious. Consider you want to model a Tree data structure, which consists of Node objects. These can be InnerNode objects (which have child nodes) or LeafNode objects (which have no children).

Such a class could be implemented like this:

class Tree {

    // The private interface
    private interface Node {
        List<Node> getChildren();
    }      

    // Both are public implementations
    public class InnerNode implements Node {
        @Override 
        public List<Node> getChildren() {  
            return Arrays.<Node>asList(getLeafNode(), getLeafNode());
        }
    }
    public class LeafNode implements Node {
        @Override 
        public List<Node> getChildren() {  
            return Collections.emptyList();
        }
    }

    // These return the concrete, public types
    public InnerNode getInnerNode() { return new InnerNode(); }
    public LeafNode  getLeafNode()  { return new LeafNode();  }

    // This returns the private interface type
    public Node getRootNode() { 

        // Both concrete types can be returned here,
        // because they both implement the interface
        return getInnerNode(); // Works 
        //return getLeafNode(); // Works
    }

    // This uses only the interface type
    public void traverseNode(Node node) {
        System.out.println("Traversing "+node);
        for (Node child : node.getChildren()) {
            traverseNode(child);
        }
    }
}

In an external main method, you can observe the limitations imposed by the private interface:

public static void main(String[] args) {
    Tree tree = new Tree();

    // The public concrete types can be used
    Tree.LeafNode  leafNode  = tree.getLeafNode();
    Tree.InnerNode innerNode = tree.getInnerNode();

    // The private interface can not be used from outside:
    //Tree.Node node = tree.getRootNode();

    // This is possible: The class only uses its 
    // own private interface here
    tree.traverseNode(tree.getRootNode());
}

In this example, you can call traverseNode, passing in the Node that is returned by getRootNode, regardless of whether this node is a InnerNode or a LeafNode. In the current version, this will print something like

Traversing Tree$InnerNode
Traversing Tree$LeafNode
Traversing Tree$LeafNode

If you changed getRootNode to return a LeafNode, then it would only print

Traversing Tree$LeafNode

To put it simply, and as the name "private interface" already suggests: You can use this in order to hide the fact that two classes share a common ancestor.

Subset answered 20/12, 2014 at 12:41 Comment(0)
A
1

I have investigated in to this issue and able to find some more information. The following is a practical example

enter image description here

The SaveInterface class is a type (i.e. a class with no implementation, all its methods are abstract). It has one public member function called SaveData(). The Document class from the initial solution now implements the SaveInterface type in a manner which keeps the SaveData() method from being accessible to clients of Document.

Notice that, in this solution, SaveHandler does not have a navigable association with the Document class. This has been replaced with a navigable association to the SaveInterface class. Since SaveData() is declared publicly in the SaveInterface class SaveHandler no need to be declared as a friend of the Document class.

Since the SaveHandler class is not a friend of the Document class it does not have the ability to change any of its private member variables or call any of its private member functions. So the encapsulation of the Document class has been preserved. The SaveHandler class no longer even needs to know about the Document class since it now depends on an interface called SaveInterface. This reduces the overall dependencies in the design and creates a potential for reuse.

Participants

Target (Document)

  • defines the public interface for the client.
  • constructs the RequestHandler (SaveHandler) object and passes to the RequestHandler an instance of the RequestInterface (SaveInterface) class. − in the motivating example, the Document class exports an interface that allows clients to start asynchronous saves.

Client

  • clients use the exported Target interface to perform specific functions.

Command

  • the Command interface is employed because it is likely that the Target interface will want to create many different kinds of RequestHandler objects. If all of these objects implement the Command interface then a Factory2 could be used to create the individual RequestHandler objects.

RequestHandler (SaveHandler)

  • created with a reference to the RequestInterface. implements the Command interface so the Target class can call the Execute() member function to perform the request.

  • in the motivating example, the SaveHandler class is used to create a separate thread of execution and then call a member function defined in the SaveInterface to actually save the data in the Document in the newly created thread.

RequestInterface (SaveInterface)

  • specifies an abstract interface for a particular request.

enter image description here

Known Uses

This pattern is used extensively in an embedded real-time environment at Xerox. It is employed in order to break the thread of execution in classes that perform various services for their clients.

For More info : http://www.objectmentor.com/resources/articles/privateInterface.pdf

Acaroid answered 30/12, 2014 at 4:45 Comment(0)
N
0

A private interface is a way to force a class to implement some methods, without publicly exposing that this interface is implemented - e.g., you won't be able to create a List<MyPrivateInterface> and add instances of your class to it.

Niece answered 20/12, 2014 at 11:43 Comment(3)
Yes it is true. But how could it clarify that when private interfacs are used, it allows us to avoid "adding any type information (that is, without allowing any upcasting)." That is what i'm trying to figure it out. Thank You for your clarification.Acaroid
It just means, that if you have Foo.Bar as a private interface, and an object of type Foo.Baz implements Foo.Bar, then code outside of Foo can use that object as an instance of Baz, but cannot (up)cast it to Bar. Fairly obvious note, really. I think, the reason you do not understand it is that you are looking for some hidden meaning, that just isn't there.Repute
I think he doesn't know what does upcasting mean.Edieedification
R
0

I think, the question is why you would want to "force" your own class implement anything? I mean, it's your class, if you want it to implement a method, just implement it. "Private INTERface" is just a misnomer. An interface is the view of your class that you want to expose to outside. Making it private serves no purpose whatsoever.

If you are asking about "package private" interfaces, that's kinda different, although not much. You might want sometimes to implement an interface, that is internal to your implementation and is not exposed to the outside. It is pretty hard (albeit, not impossible) to come up with an example where it would be useful though.

Repute answered 20/12, 2014 at 11:53 Comment(1)
Yeah. I accept the fact that private interfaces are kind of a "misnomer". I just wanted to make sure that I understand it correctly. May be I'm missing out the whole point of using "private interfaces".Acaroid

© 2022 - 2024 — McMap. All rights reserved.