views:

253

answers:

8

Hi All,

I have got a question in my finished interview that I wouldn't get the right answer.

Assume that we have 3 class, Base, Derivate1 and Derivate 2, Their relations are shown as follow

public class Base {...}

public class Derivate1 extends Base {...}

public class Derivate2 extends Derivate1 {...}

Then we found out that Derivate1 and Derivate2 are unnecessary for our program, but their method implementations are useful. So, how can we get rid of Derivate1 and Derivate2 but still keep their methods? In this case, we are expecting that user cannot create new instance of Derivate1 and Derivate2, but they still can use the method implementations in Derivate1 and Derivate2. Of course, we are allow to change the code in class Base.

What do you think about that and can you tell what they're actually asking?

Thanks a lot.

PS.

There are abit of hints from my interviewer when I have discuss the them.

  • The derivate classes are from the third party. They are badly design, so we don't want our client to use them, which means user should not allow to create instance from the derivate classes.

  • The derviate class contains overriding methods that are useful for the Base class, we can create method with different name in the Base to implement those useful behavious in derviated classes.

And thank you for all those interesting answers...

A: 

I think they meant extracting derivate to interface

Xorty
Would you able to elaborate a bit of your thought? I think interface does not allow to have implementation.
Bob
they don't, copying code from old Derivate class implementing new Derivate interface. In case you would like to switch back, you just create another implementation of that interface.
Xorty
But I don't thing this can stop user of this code create new instance of derivated classes, right?
Bob
There will be no more derivated class, it will be extracted to interface. You can just create class witch implements that interface.
Xorty
+2  A: 

Simple refactoring:

  1. Copy all code from Derivate1 and Derivate2 into Base.
  2. Delete Derivate1 and Derivate2 classes
  3. Ensure no missing references (if you are already holding pointers to Derivate objects as Base, you should be good)
  4. Compile
  5. ?????
  6. Profit!

Even if you have more subclasses such as Derivate3 and Derivate4 down the hierarchy, there should be no problem in having them extend Base.

Yuval A
Was that reference to South park gnomes? :) Collect underpants, ???? , profit!
Xorty
`<!-- no comment -->` :)
Yuval A
+2  A: 

(non-static) Methods from Derivate1 and Derivate2 are only usable if we create Derivate1 and Derivate2 instances. Creating a Base instance (like with new Base()) will not give access to (non-static) method declared in subclasses.

So to keep the methods, one could add (refactor) them to the Base class. If we just don't want public constructors for the sub classes but keep the object graph as it is, on could use a Factory pattern to have them created on demand. But even in this case one had to cast the object returned by the factory to either Derivate1 or Derivate2 to use the (non-static) methods.


I guess I know what they wanted to hear, the common recommendation 'favour composition over inheritance'. So instead of saying Derivate1 is-a Base you do a Derivate1 has-a Base:

public class Derivate1 {
  private Base base;

  // ... more
}

public class Derivate2 {
  private Derivate1 derivate1;

  // ... more
}

No more inheritance and both Derivates can still use methods of their former super classes.

Andreas_D
Sorry mate, they have clearly ruled out the composition solution of the derivate class. What they want just want to get ride of the unnecessary inheritance and bad design of the derivate classes, but keeping the useful function in the Base. Another hint they gave me is the userful method in Derivate class overrides methods in Base, so it would be possible to implement those methods in different name in Base. I was getting more confuse at this point, so I give up til here, but they still refuse to give me a answer. Hope this can help
Bob
@Bob, you should have mentioned those things in your question (no composition, Derivates are inherited by unknown classes).
Andreas_D
yes! I should... but I seems like I can update my question anymore
Bob
hmm - can't you see the 'edit' link just below your question? I thought one can edit his own question even with just 1 rep point (nothing else is mentioned in the FAQ)
Andreas_D
A: 

If it makes sense, you can directly include these methods in your base class. But it depends on the meanings of this class, of course. If it is possible, you could ty to use static methods in a utility class. By the way, your developers will have to change their use of the API in both cases.

Agemen
Yes, that would do, but how can we get ride of the inheritance, which mean the user shouldn't be able to create instance of derivated classes.
Bob
A: 

The first obvious thing is that each of the classes in the hierarchy is concrete - in general, either a type should be abstract, or a leaf type. Secondly, there isn't quite enough information as to what these methods are - if they override something in Base or Derived1, you can't move them into Base; if they are utility methods which would apply to any Base then they might be moved into Base, if they are independent of Base then then they could be moved into a helper class or a strategy.

But I would question the idea that a class is not required but its behaviour is - it sort of implies that the questioner is looking at designing an ontology rather than an object oriented program - the only reason a class exists is to provide behaviour, and coherently encapsulating a useful behaviour is a sufficient and necessary condition for a class to exist.

Pete Kirkham
The thing is, since we are not allowing to delete the inheritance relation for the code, (otherwise would be a really dump question), so one of the question is how to stop user's creating the instance of derivate class. I am actually expecting a design pattern question. As Andreas_D say, we can refactory the constructor into private, then provide a factory method to create instance for user.
Bob
@Bob it varies what you are trying to do. There needs to be a justification why you want to get rid of the inheritance before you can decide whether to replace with a strategy or a helper rather than making it an abstract base. As I said, normally you would expect all classes to be abstract or final; that *is* the pattern for stopping the creation of classes which exist for derivation.
Pete Kirkham
+1  A: 

We could do two things:

  • we could pull up some methods of Derivate1 and Derivate2 to Base, when this makes sense (as noted above)
  • we could make both Derivate1 and Derivate2 abstract: this prevents instantiation, but not inheritance
MarcoS
+2  A: 

From the hints they gave you, I think the answer was adapter pattern, which sometimes is used for legacy code.

You can have a look at it here:

http://en.wikipedia.org/wiki/Adapter_pattern

Pau
Exactly what I was thinking. +1
George Marian
A: 

Since you do not own the derivate classes you cannot delete them. The base class is all yours so you have control. The client is yours so you have control there. So the best way would be to have an all new class that is exposed to the client. This class essentially creates the derivate instances (note: your client isn't dealing with it anymore) and use their useful functions.

neal aise
Ah, yes...the Adapter pattern.
George Marian