[Interest] QLineEdit upper case

Till Oliver Knoll till.oliver.knoll at gmail.com
Fri Aug 8 20:14:34 CEST 2014


Am 08.08.14 18:08, schrieb pmqt71:
> ...
> @Oliver:
> yes my problem is that QLineEdit can have only 1 validator. I think
> inherithance should be easier than implementin a ChainValidator, am I right?

We could now fill pages of discussions about "Inheritance being evil",
"is-a" vs "has-a" vs "uses-a" relations etc., and we'd end up having at
least 10 times more opinions than possible ways of implementing the
solution ;)

(Just start by asking Google with "Inheritance is Evil" - and you get
the idea ;))

Here is just a starter link:

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


Personally I try to question inheritance as much as possible. The
classic question is "Is a Square also a Rectangle"?

The best practical explanation - and design question you should ask
yourself whenever you have inheritance in mind - I ever read is: would
an instance of a derived class pass all (possible and sensible) unit
tests of a base class?

Let's continue with the "Shall I derive my Square class from the
Rectangle class?"-example (which is really a classic, but as such
probably also of "academic value") and let us further assume there was a
unit test which would verify the "area" method.

So the test would look something like:

  int width = 3;
  int height = 5;
  Rectangle rect;

  // setup
  rect->setWidth(width);
  rect->setHeight(height);

  // exercise
  int area = rect.area();

  // verify
  assert(area, width * height);


Now if you ran the same test, but with an instance of Square, that test
would fail! Why? Because our expectation is that whenever you modify
either width or height, the implementation of a Square would implicitly
set the height or width respective to the same value (otherwise the
instance would not be a square!).

So after setting the height to 5, the width in above example would also
become 5 and the area would be 25 != 15. Fail.


Now would e.g. a UPPERCaseValidator inherited from a
LettersOnlyValidator also falsify unit tests in the same way? Most likely.



There is another reason why particularly in this example I would
definitively opt for the "ChainValidator" (-> composition): it is way
more flexible!

Let's assume you had 3 validators A, B and C and an additional
"UPPERCaseValidator" (4 classes in total). If you wanted to have for
each A, B, C Validator a combination, you'd have to come up with another
3 classes (deriving each time from A, B and C respective)! So that would
be 7 classes in total to maintain (and if you need to fix something in
your UPPERCaseValidator implementation, you'd need to fix it 3 times in
the worst case - you could share parts of the implementation, but still...).


With a composition pattern you'd only need one extra class - a
"ChainValidator" - and you could combine either A, B or C with your
UPPERCaseValidator. Only one additional class, total 5 classes.

"Well, 5 or 7 classes", what's the big deal anyway!

Well, here is the deal: just add one more validator D, and your number
of classes grows linearily (and so are the number of implementations to
maintain): not only do you have another class D, but also a new derived
class from D - total 9 classes! For every "base validator" class that
you'd add you would have to implement yet another derived class
(assuming off course that this would make sense to have an
UPPERCaseValidator also validate the output of all A, B, C and D classes).


But here's an even bigger deal: Let's assume your boss now tells you
that you need to validate A, B - AND C! Or any combination thereof
(boss: "Oh and yes, off course, don't forget about our new shiny
UPPERCaseValidator class, add that to the mix, too! And the new
validator D that we just purchased yesterday...").

So would you want to come up with classes such as ABCUpperCaseValidator,
CBAUpperCaseValidator, AUpperCaseValidator, BUpperCaseValidator,
CUpperCaseValidator, ... (the names reflect the "inheritance chain")?
Hopefully not! A combinatorial explosion of possible inheritance
permutations!


With the "ChainValidator" however you would simply assemble the
validators like so (pseudo-syntax - you get the idea):

  AValidator a;
  BValidator b;
  CValidator c;
  UPPERCaseValidator d;
  ChainValidator ca;


  // validates a and d
  ca.add(a);
  ca.add(d);
  state = ca.validate(theString, pos);

  ca.clear();

  // validats a, c and d
  ca.add(a);
  ca.add(c);
  ca.add(d);
  ca.validate(theOtherString, pos);


No need to come up with new classes! And just one single
UPPERCaseValidator implementation!

(Again, whether the above actually works when it comes to validation, I
don't know - clearly there would be combinations which would not make
sense at all, but in the worst case you'd probably just get an Invalid
state with /any/ input).



Now all that said: the above might be complete "over-engineering" in
your particular case! If you have 2 or 3 very specific cases to validate
"in just that particular dialog" and "I will never ever have the need to
ever re-use those inhertited validation classes anywhere - I swear!"
then go for inheritance - it is not "per se evil" ;) Just know the
consequences.


Cheers, Oliver




More information about the Interest mailing list