1

I have blocks performing calculations using a function step(). The blocks can be connected to each other with connect(Block).

interface Block {
    void connect(Block b);
    void step();
}

However from within a concrete block implementation (e.g. in step) it should be possible to read from the connected block:

class ABlockImpl implements Block {
    private Block src; // link to the block this block is connected to
    public void connect(Block b) {
        src = b;
    }

    public void step() {
        double x = src.read(); // XXX src is of type Block and there is no read() in Block
        /* ... */
    }

    public double read() {
        return 3.14;
    }
}

Since there is no read() in Block, this won't compile. For clients the "public" Block interface is sufficient, I need read only internally. I could add read to the Block interface, but to me this feels wrong.

Since there are multiple different implementations of Block, I cannot cast src to ABlockImpl before the call to read.

Is there an alternative way to "hide" read?

Micha Wiedenmann
  • 19,979
  • 21
  • 92
  • 137
  • Please rephrase the title and question, it is misleading and I had to read it 3 times to get what you mean. – Sentry Jan 17 '13 at 14:47
  • Do you have a suggestion, I was thinking mostly about how to phrase it. – Micha Wiedenmann Jan 17 '13 at 14:55
  • It sounds like you just want one class to implement two different interfaces, but I think you want an interface that is not public, am I right? – Sentry Jan 17 '13 at 14:59
  • I am not sure. I think I want a public interface without `read` and a way for blocks to still `read` from each other. – Micha Wiedenmann Jan 17 '13 at 15:07
  • 2
    I dont think you can or want to do this with an interface. Clients can provide their own implementations of Block, therefore `read()` has to be part of the interface. It sounds as if you want to provide all implementations yourself. I would therefore propose you publish an abstract class with a private `read()` or something. – Johannes Luong Jan 17 '13 at 15:13
  • I provided a possible solution as an answer – Sentry Jan 17 '13 at 15:17
  • Is there anything that forbids an abstract class instead of an interface? – Sentry Jan 18 '13 at 09:52
  • No, not that I can tell. – Micha Wiedenmann Jan 18 '13 at 11:13
  • Then, you could define an abstract class, which implements none of the methods, but declares them with differen visibility. All subclasses of it would need to implement the methods, but `read` could stay hidden. – Sentry Jan 18 '13 at 12:23

3 Answers3

6

You can have a public interface and a package local one

public interface MyPublicInterface {

}

interface MyDirectInterface extends MyPublicInterface {

}

class MyImpl implements MyDirectInterface {

    public void add(MyPublicInterface mpi) {
         MyDirectInterface mdi = (MyDirectInterface) mpi;
         // use mdi
    }

}
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • When I change the type of `src` to `MyDirectInterface` I can no longer assign `src` in `connect(Block)`, since the caller gives me a public interface instance. – Micha Wiedenmann Jan 17 '13 at 15:05
  • 1
    You have to cast the public interface to the private one on the assumption that all implementations of the public interface implement the private one. I have added an example. – Peter Lawrey Jan 17 '13 at 15:20
  • In this case I would rather add `read` to the interface, do you agree? – Micha Wiedenmann Jan 17 '13 at 15:54
  • You could document that the method is for internal use, if believe the developers will read it. You could give it a surprising name like `$read` or `read$` – Peter Lawrey Jan 17 '13 at 16:24
  • Should I delete my question since there is no answer to it or what should I do? – Micha Wiedenmann Jan 17 '13 at 16:38
  • If there wasn't an answer to your problem, I wouldn't have given one ;) – Peter Lawrey Jan 17 '13 at 16:44
  • No, there is no correct answer. Even if you make the interface itself non-public, all methods a class has to implement because of this interface are public again. See http://stackoverflow.com/questions/4801642/java-tutorial-says-i-can-have-a-package-private-interface-but-i-cant – Sentry Jan 18 '13 at 09:19
  • @Sentry you cannot access a public method which is only exposed by an package local interface or class. (Except by using reflection in which case you can do almost anything) – Peter Lawrey Jan 18 '13 at 09:25
  • @PeterLawrey True, but he didn't say that the implementation class is package local. It is in the code example, but I don't think this is part of the requirement. The moment the class itself is public, the method itself is accessible. – Sentry Jan 18 '13 at 09:52
  • @Sentry True, but in his example and mine the class is package local. I wouldn't say there is no correct answer, just because you have to do something specific to make it work. – Peter Lawrey Jan 18 '13 at 09:56
  • 1
    @PeterLawrey Yes, but if the class _needs_ to be public, your solution wouldn't work anymore. I mean, it's better than what I came up with so far, but I think this should be pointed out. – Sentry Jan 18 '13 at 12:22
2

You could create abstract layer between interface and concrete implementations of block and name it, for example, BlockAdapter.

I.e.:

interface Block {
    void connect(Block b);
    void step();
    double read();
}

...

public abstract class BlockAdapter implements Block { 
    double read() {
          return -1; // ? something like that
    }
}

...

public class ABlockImpl extends BlockAdapter { ... }
Andremoniy
  • 34,031
  • 20
  • 135
  • 241
  • I thought the idea was to not have `read()` in the interface? – Johannes Luong Jan 17 '13 at 14:57
  • @JohannesSchad I think, that author possibly doesn't want it because in common case he must add this method implementation to all subclasses. `Adapter` pattern allows do it in only one layer and override this method in only desired subclasses. – Andremoniy Jan 17 '13 at 14:59
  • No, I don't want to have `read` in the interface (if that is possible). – Micha Wiedenmann Jan 17 '13 at 15:06
  • Why don't you remove `read` from the interface, but define it `protected` in the abstract class? – Sentry Jan 18 '13 at 09:21
  • I defined it not `protected`, but `package local`. Indeed, may be it would be better to define it `protected`. I did that because author of the question said: *I need `read` only internally.* – Andremoniy Jan 18 '13 at 09:23
0

I don't think there is a solution that gives you exactly what you want, but maybe something close to it:

interface Block {
    void connect(Block b);
    void step();
}
interface ReadableBlock extends Block {
    double read();
}

The method read() still needs to be public, but you can let the exterior code only refer to implementations via the Block interface, while the implementation itself is from ReadableBlock

public cass ABlockImpl implements ReadableBlock {
    ....
}
Block b = new ABlockImpl();
Sentry
  • 4,102
  • 2
  • 30
  • 38