Adding functionality to an existing class in OOP

With object oriented programming, we often use polymorphism to make several different types of objects behave under the same ‘interface’. The bread and butter example is like so:

public abstract class Animal {
    public abstract void makeSound();
}

public class Dog extends Animal {
    public void makeSound() {
        System.out.println("Woof woof");
    }
}

public class Cat extends Animal {
    public void makeSound() {
        System.out.println("Meow");
    }
}

We don’t care what the actual animal is, only that it can make a sound.

However the problem occurs when we want to add a new feature to existing classes.
In my case, I seek to make several classes implement the UniformProvider interface (it converts the class to a raw uniform value for an OpenGL shader program).

Up until now I have used a simple instanceof check that handles a number of possible types, however I don’t want to rely on instanceof as it is not easily extensible without modifying the source file.

The problem with the UniformProvider interface is that it cannot be implemented for built in types like float (or Float), int (or Integer), and arrays of objects (eg: Matrix4f[]). Furthemore, I believe putting the functionality for uniform variable conversion into mathematics classes violates the Single Responsibility Principle.

In the Rust language, structs have a useful feature that I’ve now just realised the potential of. In traditional OOP, the class/struct implements the interface/trait, and more interfaces can’t be implemented without modifying original file. However in Rust one provides and implementation of a trait for a struct, thus reversing the dependency. This uses the syntax like impl Add for Vector4f instead of Vector4f implements Add.

I am pondering what options exist in traditional OOP languages such as Java or C++ for such a pattern. I considered creating a registry of converters, that are assigned to a class: eg FloatConverter for float, and then accessing the relevant converter using a HashMap or equivalent, but I thought this might be quite inefficient.

I ask what solutions for this dilemma are out there (or if I should just switch to Rust 🙂 [I’m thinking of anyway]).


Source: oop

Leave a Reply