"Il y a peu de choses qui me soient impossibles..."
Stevens Miller wrote:Is this a legitimate way to enforce a pair-wise restriction on classes, or am I missing something better here? (Or a problem with this approach altogether?)
"Leadership is nature's way of removing morons from the productive flow" - Dogbert
Articles by Winston can be found here
Winston Gutkowski wrote:If however, it genuinely is something to do with a "type" that cuts across an existing hierarchy, then one possibility would be to use a marker interface.
However, they should be used very sparingly.
Perhaps if you could come up with a real-life example it might be a bit clearer, but I doubt that there's a single "magic bullet" answer to this question.
HIH
"Il y a peu de choses qui me soient impossibles..."
Stevens Miller wrote:...it struck me that it imposes an obligation on programmers who will be calling the marry method to add the markers, whereas, if they are subclassing the various Parent* classes to create the instances they are passing to marry(), each of those subclasses is already "marked" with the class of its superclass (that is, the programmer can't forget to mark a class as being IS-A member of its superclass).
"Il y a peu de choses qui me soient impossibles..."
Stevens Miller wrote:I thought about that, but I am also aware of the general skepticism that accompanies their use, and it struck me that it imposes an obligation on programmers who will be calling the marry method to add the markers, whereas, if they are subclassing the various Parent* classes to create the instances they are passing to marry(), each of those subclasses is already "marked" with the class of its superclass (that is, the programmer can't forget to mark a class as being IS-A member of its superclass).
"Leadership is nature's way of removing morons from the productive flow" - Dogbert
Articles by Winston can be found here
Winston Gutkowski wrote:Now it's by no means the only way to do it, but I think (?) it solves your problem.
"Il y a peu de choses qui me soient impossibles..."
Stevens Miller wrote:It does. Winston, you're a genius. (But you knew that, right? )
"Leadership is nature's way of removing morons from the productive flow" - Dogbert
Articles by Winston can be found here
"Il y a peu de choses qui me soient impossibles..."
Stevens Miller wrote:That works. Now, I actually don't want those interfaces to be visible outside the package where AbstractFilter is defined (no one else would ever need them, and I don't want anyone tricking my connect() method into accepting something not derived from AbstractFilter). So, I made them package-private. This, alas, provokes one of those, "exporting not public type through public API" warnings at Line 31 (of your first code listing). This is a case where I think I can live with that, however. Also, before doing the actual connection, I need to cast from and to to type AbstractFilter, as that's the class with the methods needed to build the list. Heh, I suppose I could put the method signatures into ConnectTo and ConnectFrom, couldn't I? Then I could skip the cast and also stop feeling guilty about using marker interfaces!
"Leadership is nature's way of removing morons from the productive flow" - Dogbert
Articles by Winston can be found here
Winston Gutkowski wrote:What about making them protected? If they're nested inside Connector (which I assume is final), that shouldn't be a problem, and outside Connector, they'll be package-private.
"Il y a peu de choses qui me soient impossibles..."
Stevens Miller wrote:I'll probably regret this (looking at you, Stephan van Hulst ),
"Il y a peu de choses qui me soient impossibles..."
Stephan van Hulst wrote:The RandomAccess marker interface was already mentioned. A much better solution would have been if the List and Map interfaces had isRandomlyAccessible().
"Leadership is nature's way of removing morons from the productive flow" - Dogbert
Articles by Winston can be found here
Winston Gutkowski wrote:That turns the business of "being randomly accessible" into a procedure, not something that's an intrinsic part of the type.
Stephan van Hulst wrote:To me it seems everything can be resolved if you treat *everything* as a Filter, and a filter isPassive() or isActive() (pull/push), and a filter isSource() or isSink() (or both).
"Il y a peu de choses qui me soient impossibles..."
Stephan van Hulst wrote:
Winston Gutkowski wrote:That turns the business of "being randomly accessible" into a procedure, not something that's an intrinsic part of the type.
I see what you mean. If this is the case, I much rather prefer the use of annotations instead.
"Il y a peu de choses qui me soient impossibles..."
Stephan van Hulst wrote:I see what you mean. If this is the case, I much rather prefer the use of annotations instead...
"Leadership is nature's way of removing morons from the productive flow" - Dogbert
Articles by Winston can be found here
Stevens Miller wrote:I held off on the strength of your advice that my superclass shouldn't include functionality not used by every subclass, but maybe I misunderstood what you were telling me. As it stands now, all Sources and Sinks are actually subclasses of AbstractFilter. The Sources just have null as their own source, and the Sinks have null as their sinks.
The AbstractFilter is package-private, while the Source, Sink, and Filter classes (all being subclasses of AbstractFilter) are public.
The (now public) marker interfaces give me compile-time type-safety regarding which classes can be connected, without directly exposing AbstractFilter to client code. Seems to work, and (I think) I understand it.
I've tried a couple of times to read up on annotations, but never seem to quite get what they are, much less how I can use them myself. But, a couple of folks have now suggested this might be a good tool to use in solving my type-safety issue.
Stephan van Hulst wrote:This is unfortunate. Source, Sink and Filter sound like they should be interfaces, and AbstractFilter sounds like something that should (partially) implement Filter, Source and Sink.
...
I really still don't understand why a Source doesn't just declare methods to get something from it, and Sink has methods to put something in it. You can also make them push-based by adding events to these interfaces.
"Leadership is nature's way of removing morons from the productive flow" - Dogbert
Articles by Winston can be found here
Stephan van Hulst wrote:
Stevens Miller wrote:I held off on the strength of your advice that my superclass shouldn't include functionality not used by every subclass, but maybe I misunderstood what you were telling me. As it stands now, all Sources and Sinks are actually subclasses of AbstractFilter. The Sources just have null as their own source, and the Sinks have null as their sinks.
No, that still sounds iffy to me :P
The AbstractFilter is package-private, while the Source, Sink, and Filter classes (all being subclasses of AbstractFilter) are public.
This is unfortunate. Source, Sink and Filter sound like they should be interfaces, and AbstractFilter sounds like something that should (partially) implement Filter, Source and Sink.
"Il y a peu de choses qui me soient impossibles..."
Stevens Miller wrote:Well, now I'm confused again. If Source, Sink, and Filter are interfaces, and AbstractFilter only partially implements them, what implements the rest?
"Leadership is nature's way of removing morons from the productive flow" - Dogbert
Articles by Winston can be found here
Winston Gutkowski wrote:Perhaps if you could explain to us in layman's terms (and sorry if this seems like repetition), what these classes are trying to do, it might give us a better handle on the design.
"Il y a peu de choses qui me soient impossibles..."
"Il y a peu de choses qui me soient impossibles..."
Stevens Miller wrote:I know you asked for a layman's description, but, expressed as a problem in pure Java, apart from what I'm trying to do, the question is: How might I refactor the following code so the getMySource() and getMySink() methods are defined only once each?...
"Leadership is nature's way of removing morons from the productive flow" - Dogbert
Articles by Winston can be found here
Winston Gutkowski wrote:I think the problem here is that you already have an idea in your head about what you want things to look like in Java, and you're trying to make the design fit that pattern.
1. Why does the framework have to support both "push" and "pull" models? Clearly you have something that is spitting out objects, and something that accepts them, but does either "thing" really care what model is used to process them?
2. It strikes me that this framework is missing generics. Might it not be better to have the Source specifiy what it's spitting out? - ie: Source<T> (or in your case, Source<VideoFrame>).
3. Are you on version 8? Because I have a feeling that this problem might fit very nicely into the Stream/lambda or Stream/function model. Unfortunately, I haven't read up too much on it myself yet, so I can't really advise you exactly how; but it certainly "smells" like Stream might be a good fit. And then you don't have to worry about "sources" and "sinks".
Alternatively, what about a Deque? Java already has a few existing implementations, both blocking and non-, and all you'd need to do to create a Filter (which appears to be the only thing that actually "changes" objects) is add some kind of "function" that performs the process either (a) when an object is placed in the queue, or (b) when it's "pulled" from it (possibly better).
HIH. Fun thread.
"Il y a peu de choses qui me soient impossibles..."
"Il y a peu de choses qui me soient impossibles..."
"Il y a peu de choses qui me soient impossibles..."
Stevens Miller wrote:but someone hereabouts convinced me, a year or two back, that I was underestimating Java's ability to do the same thing (that was you, btw )...
"Leadership is nature's way of removing morons from the productive flow" - Dogbert
Articles by Winston can be found here
Stevens Miller wrote:btw, I see that you, Stephan, are in Enschede, The Netherlands, and Winston is in London...
"Leadership is nature's way of removing morons from the productive flow" - Dogbert
Articles by Winston can be found here
"Il y a peu de choses qui me soient impossibles..."
Winston Gutkowski wrote:My SP maybe (British Telecom), but I'm 400 miles away in the wilds of Scotland, where it's-a-blowin' something fierce tonight.
"Il y a peu de choses qui me soient impossibles..."
Stevens Miller wrote:Scotland? Whereabouts? I was fortunate enough to take a business trip to Aberdeen...
"Leadership is nature's way of removing morons from the productive flow" - Dogbert
Articles by Winston can be found here
Winston Gutkowski wrote:A little place called Girvan...
"Il y a peu de choses qui me soient impossibles..."
Did you see how Paul cut 87% off of his electric heat bill with 82 watts of micro heaters? |