Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Abstract vs Empty method

I need to add one optional method in existing abstract class that is extended by more than 50 classes:

public abstract class Animal{...}

This method is not used by all those classes, but in the future it probably will.

The structure of one of my classes is:

public class Dog extends Animal {...}

The cleanest way is using abstract method but it obliges me to change all existing classes.

The workaround is to create "empty" method in abstract class:

public String getString(Map<String, Object> params){
       return "";
   }

and then override it when I need in classes that extend abstract class.

Is there any better solution?

like image 555
NikNik Avatar asked Feb 01 '26 12:02

NikNik


2 Answers

Having an "empty" method is fine. But in order to be sure, that it will be implemented where it is really needed, consider throwing an exception by default from this method:

    throw new UnsupportedOperationException();

A similar approach is used in java.util.AbstractList class:

public E set(int index, E element) {
    throw new UnsupportedOperationException();
}
like image 182
Andremoniy Avatar answered Feb 04 '26 02:02

Andremoniy


I can't help feeling like you have some architectural/design issues here, but without knowing more, I can't say for sure. If 50 classes are going to inherit from Animal, but not all of them are going to use this method, then I'm wondering if they should really inherit from one common class. Perhaps you need further levels of sub-classing... think Kingdom->Phylum->Sub-Phylum. But my gut says that's still not the right answer for you.

Step back - what are you trying to accomplish? If you're going to implement this function on these classes in the future, then you must also be changing your code to know to use/expect this. The point of inheritance is to allow code to refer to an object's expected common behavior without knowing what type of object it's referencing. In your getString() example, you might have a function as such:

public string SendMessage(Animal someAnimal) {

    string message = someAnimal.getString();

    //  Send the message

}

You can pass it a dog, a cat, a platypus - whatever. The function doesn't care, because it can query the message from its base class.

So when you say you'll have animals that don't implement this message... that implies you'll have logic that ensures only cats and dogs will call this function, and that a platypus is handled differently (or not at all). That kind of defeats the point of inheritance.

A more modern approach would be to use interfaces to establish a "has a" relationship instead of an "is a" relationship. A plane might have an IEngine member, but the specific type of engine can be set at run-time, either by the plane class itself, or by the app if the member is writeable.

public interface IEngine {
    string getStatus();
    string getMileage();
}

public class Cessna {
    public IEngine _engine;

    public Cessna() {
        _engine = new PropellerEngine();
    }

}

You could also inherit directly from that interface... Animals that don't implement IAnimalMessage wouldn't implement that function. Animals that do would be required to. The downside is that each animal will have to have its own implementation, but since your base class currently has an abstract function with no body, I'm assuming that's a non-issue. With this approach, you can determine if the object implements the interface as such:

IAnimalMessage animalMessage = myPlatypus as IAnimalMessage;

//  If your playtpus doesn't implement IAnimalMessage, 
//  animalMessage will be null.
if (null != animalMessage) {
    string message = animalMessage.getString();
}


public interface IAnimalMessage {
    string getMessage();
}

public class Platypus : IAnimalMessage {
    //  Add this implementation when Platypus implements IAnimalMessage...
    //  Not needed before then
    public string getMessage() { 
        return "I'm a cowboy, howdy, howdy, howdy!";
    }
}

That's probably the closest to what you're asking for I can suggest... classes that don't need the message won't implement that interface until they do, but the code can easily check if the interface is implemented and act accordingly.

I can offer more helpful/specific thoughts, but I'd need to understand the problem you're trying to solve better.

like image 43
James King Avatar answered Feb 04 '26 02:02

James King