Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best way to add functionality to built-in types

Tags:

java

oop

I wonder what is the best way in terms of strict OOP to add functionality to built-in types like Strings or integers or more complex objects (in my case the BitSet class).

To be more specific - I got two scenarios:

  1. Adding a md5 hashing method to the String object
  2. Adding conversion methods (like fromByteArray() or toInteger()) to the BitSet class.

Now I wonder what the best practices for implementing this would be.

I could e.g. create a new Class "BitSetEx" extending from BitSet and add my methods. But I don't like the idea since this new class would need describing name and "BitSetWithConversionMethods" sound really silly.

Now I could write a class consisting only of static methods doing the conversions.

Well I got a lot of ideas but I wan't to know what would be the "best" in sense of OOP.

So could someone answer me this question?

like image 295
tyrondis Avatar asked May 15 '11 14:05

tyrondis


1 Answers

There are a few approaches here:

Firstly, you could come up with a better name for the extends BitSet class. No, BitsetWithConversionMethods isn't a good name, but maybe something like ConvertibleBitSet is. Does that convey the intent and usage of the class? If so, it's a good name. Likewise you might have a HashableString (bearing in mind that you can't extend String, as Anthony points out in another answer). This approach of naming child classes with XableY (or XingY, like BufferingPort or SigningEmailSender) can sometimes be a useful one to describe the addition of new behaviour.

That said, I think there's a fair hint in your problem (not being able to find a name) that maybe this isn't a good design decision, and it's trying to do too much. It is generally a good design principle that a class should "do one thing". Obviously, depending on the level of abstraction, that can be stretched to include anything, but it's worth thinking about: do 'manipulating the set/unset state of a number of bits' and 'convert a bit pattern to another format' count as one thing? I'd argue that (especially with the hint that you're having a hard time coming up with a name) they're probably two different responsibilities. If so, having two classes will end up being cleaner, easier to maintain (another rule is that 'a class should have one reason to change'; one class to both manipulate + convert has at least 2 reasons to change), easier to test in isolation, etc.

So without knowing your design, I would suggest maybe two classes; in the BitSet example, have both a BitSet and (say) a BitSetConverter which is responsible for the conversion. If you wanted to get really fancy, perhaps even:

interface BitSetConverter<T> {
 T convert(BitSet in);
 BitSet parse(T in);
}

then you might have:

BitSetConverter<Integer> intConverter = ...;
Integer i = intConverter.convert(myBitSet);
BitSet new = intConverter.parse(12345);

which really isolates your changes, makes each different converter testable, etc.

(Of course, once you do that, you might like to look at guava and consider using a Function, e.g. a Function<BitSet, Integer> for one case, and Function<Integer, BitSet> for the other. Then you gain a whole ecosystem of Function-supporting code which may be useful)

like image 89
Cowan Avatar answered Sep 28 '22 23:09

Cowan