0

Say I have a class A

class A
{
   Z source;
}

Now, the context tells me that 'Z' can be an instance of different classes (say, B and C) which doesn't share any common class in their inheritance tree.

I guess the naive approach is to make 'Z' an Interface class, and make classes B and C implement it.

But something still doesn't convince me because every time an instance of class A is used, I need to know the type of 'source'. So all finishes in multiple 'ifs' making 'is instanceof' which doesn't sound quite nice. Maybe in the future some other class implements Z, and having hardcoded 'ifs' of this type definitely could break something.

The escence of the problem is that I cannot resolve the issue by adding functions to Z, because the work done in each instance type of Z is different.

I hope someone can give me and advice, maybe about some useful design pattern.

Thanks

Edit: The work 'someone' does in some place when get some instance of A is totally different depending of the class behind the interface Z. That's the problem, the entity that does the 'important job' is not Z, is someone else that wants to know who is Z.

Edit2: Maybe a concrete example would help:

class Picture
{
  Artist a;
}

interface Artist
{
}

class Human : Artist { }

class Robot : Artist {}

Now somewhere I have an instance of Picture,

Picture p = getPicture();
// Now is the moment that depending if the type of `p.a` different jobs are done
// it doesn't matter any data or logic inside Human or Robot
Matthew Azkimov
  • 467
  • 1
  • 4
  • 17
  • Can you please elaborate WHY you really need to know the real type of Z? As long as you know its interface (available methods, etc), you can do all you need. – Daniel Monteiro Oct 17 '12 at 22:50
  • I added some extra information. – Matthew Azkimov Oct 17 '12 at 23:01
  • @DanielMonteiro: There are many situations in which one will have a collection of objects, some of which inherit or implement `Foo`, and some of which don't, and one wish wish to perform on everything in the collection an action which can be defined for all objects, but can be done better with instances of `Foo`. Use of `instanceof` in such cases would seem to me entirely appropriate. – supercat Mar 14 '14 at 22:27
  • @supercat: creepy! I was ranting about the exact same stuff on G+ just yesterday! I completely agree with you. In fact, I created the following image to illustrate my point (https://lh6.googleusercontent.com/-BeU3FnEWg5c/UyI8C3vlfhI/AAAAAAAACog/hxrZ1OX75PQ/w318-h398-no/47183956.jpg) – Daniel Monteiro Mar 14 '14 at 23:44
  • 1
    @DanielMonteiro: It's not just for interfaces; it can also be appropriate in cases where access to another object's internals can allow speedups which cannot be achieved any other way. For example, an implementation of `List` might provide a constructor which accepts a `List`; if the passed-in object stores its data in a format the implementation knows about, the constructor can copy the data much faster than if it has to do everything through the interface. To be sure, what that shows perhaps as much as anything is that Java needs (but doesn't have) a standard means by which... – supercat Mar 14 '14 at 23:50
  • 1
    ...an array-backed type can expose an array for temporary read-only access (such a type could hold a private reference of type `Array`, subscript, and segment length, and include methods to read array elements or bulk-copy items out of the array, and include methods to set but not read the array reference [thus allowing the same ArrayReader item to be used repeatedly]. An interface like `List` could then include a method to request ask it to configure an `ArrayReader` to access part of its backing store starting at item `n`, and collections could use such methods to exchange bulk data. – supercat Mar 14 '14 at 23:55

3 Answers3

6

The point of using an interface is to hide these different implementations; A should just know the intent or high-level purpose of the method(s).

The work done by each implementation of Z may be different, but the method signature used to invoke that work can be the same. Class A can just call method Z.foo(), and depending on whether the implementation of Z is B or C, different code will be executed.

The only time you need to know the real implementation type is when you need to carry out completely unrelated processing on the two different types, and they don't share an interface. But in that case, why are they being processed by the same class A? Now, there are cases where this may make sense, such as when B and C are classes generated from XML Schemas, and you can't modify them - but generally it indicates that the design can be improved.

Updated now that you've added the Picture example. I think this confirms my point - although the implementation of getPicture() is different, the purpose and the return type are the same. In both cases, the Artist returns a Picture.

If the caller wants to treat Robot-created and Human-created pictures in the same way, then they use the Artist interface. They do not need to distinguish between Human or Robot, because they just want a picture! The details of how the picture is created belong in the subclass, and the caller should not see these details. If the caller cares about precisely how a picture is created, then the caller should paint it, not the Robot or Human, and the design would be quite different.

If your subclasses are performing totally unrelated tasks (and this is not what your Artist example shows!) then you might use a very vague interface such as the standard Java Runnable; in this case, the caller really has no idea what the run() method will do - it just knows how to run things that are Runnable.

Links

The following questions/articles suggest some alternatives to instanceof:

And the following articles also gives example code, using an example that seems similar to yours:

and the following articles discuss the tradeoffs of instanceof versus other approaches such as the Visitor pattern and Acyclic Visitor:

Community
  • 1
  • 1
DNA
  • 42,007
  • 12
  • 107
  • 146
  • As far as possible, work that relates to the class behind Z should be inside the class behind Z! That is one of the tenets of OOP. Can you give an example of what kind of classes and work you are thinking of? – DNA Oct 17 '12 at 23:04
  • My case is quite complicated, I added a more simple example – Matthew Azkimov Oct 17 '12 at 23:12
  • getPicture() is not related with any of the described classes. My case is your last pharagraph. So what 'then they use the Robot and Human concrete types' means?, use of instanceof? – Matthew Azkimov Oct 17 '12 at 23:32
  • If your case matches my last paragraph, then I don't think your example reflects this, because you only show one `getPicture()` method, implemented by both subclasses. – DNA Oct 17 '12 at 23:36
  • I never said that `getPicture()` was implemented in those subclasses. I said 'somewhere' (in the code), not 'somewhere in those classes'. Sorry if wasn't unclear. – Matthew Azkimov Oct 17 '12 at 23:39
  • My mistake; but I still think that getPicture() _should_ be implemented in the subclasses, not in another class (Picture). If there are two different ways to generate a picture, one for Robot and one for Human, then those differences belong in Human and Robot, not Picture. – DNA Oct 17 '12 at 23:55
1

I think you need to post more information, because as it stands what I see is a misunderstanding of OOP principles. If you used a common interface type, then by Liskov substitution principle it shouldn't matter which type source is.

Jean-Bernard Pellerin
  • 12,556
  • 10
  • 57
  • 79
  • That's exactly what I suspect, it not well designed in start. But I don't know how to do it either. A class that have only and only one instance of a group of classes that doesn't share any logic in common. – Matthew Azkimov Oct 17 '12 at 23:04
1

I'm gonna call your A, B, and C classes Alpha, Beta, and Gamma.

Perhaps Alpha can be split into two versions, one which uses Betas and one which uses Gammas. This would avoid the instanceof checks in Alpha, which as you've surmised are indeed a code smell.

abstract class Alpha
{
    abstract void useSource();
}

class BetaAlpha extends Alpha
{
    Beta source;
    void useSource() { source.doSomeBetaThing(); }
}

class GammaAlpha extends Alpha
{
    Gamma source;
    void useSource() { source.doSomeGammaThing(); }
}

In fact this is extremely common. Consider a more concrete example of a Stream class that can use either Files or Sockets. And for the purpose of the example, File and Socket are not derived from any common base class. In fact they may not even be under our control, so we can't change them.

abstract class Stream
{
    abstract void open();
    abstract void close();
}

class FileStream extends Stream
{
    File file;
    void open()  { file.open();  }
    void close() { file.close(); }
}

class SocketStream extends Stream
{
    Socket socket;
    void open()  { socket.connect();    }
    void close() { socket.disconnect(); }
}
John Kugelman
  • 349,597
  • 67
  • 533
  • 578
  • Some way of distinguishing between Betas and Gammas may still be required to decide whether to create a BetaAlpha or a GammaAlpha - but this could presumably be done via factory methods or a single `instanceof`...? – DNA Oct 17 '12 at 23:01