Choosing and applying the best design pattern for the particular problem

Started by
19 comments, last by nerijus ramanauskas 14 years, 1 month ago
Assume I have a template class named Sequence, which takes one template parameter. It's mainly for string buffers (or just strings) and stream buffers (unaligned byte arrays or just buffers). As it's real purpose's still undefined, we can't expect where else it could be used, it cannot even be partially specialized, although it has some methods that would only be used for strings, as well as Crop (or just sub_string), Trim, Strip, etc. But once again they can still be used somewhere else like in stream buffers (wanna play?), etc. Ok, enough introduction. The problem is about expanding/extending such the template class. Assume I want to write a specialization for the template class (ACTUALLY A DISCRETE CLASS THAT WILL JUST INHERIT THE BASE TEMPLATE CLASS `Sequence` (Sequence< char > in this particular situation)) by adding some merely-string-specific methods like Majuscule_latin_all, Compare_minuscule_latin, operator unsigned int( void ), etc. But here comes the problem and some other new problems: 1. If I want to just overload a method, I will also need to rewrite all the methods from the base class (from the template class `Sequence< char >` in this situation); 2. This is the main problem and the main purpose of this thread: if, for instance, Trim from the base class returns Sequence< char >, it is absolutely incompatible with that one class that I have "specialized" and what is more it returns the base class instance, so when users calls object_of_specialized_class.Trim() and expects it to return a new object of the same type from which user calls the method (in this case from the class we have "specialized"), it will fail and the user will start yelling with the anger it has caused. :-) What do you propose? Encapsulation? Inheritance won't help, as you see. Thanks in advance, anyway. // Wrote too fast, might be some mistakes, sorry.
Advertisement
Have you considered... composition? Or using free functions?

I'm having a hard time figuring out what you are talking about. Can you post the classes in question? It sounds like Sequence is almost like vector<>.
STL Sequence.

Note that it is not a hard class but a concept, implemented by most containers.

Algorithms to operate on the contents are in <algorithm>. They include all such trivialities as processing, trimming, cropping, etc....


General approach is often:
template < class I >void foo(I beginItr, I endItr, params ...);



There is no need for inheritance or extension.

To specialize an operation based on certain type, the following always possible:
template < class T, class A >void foo(  typename std::vector<T,A>::iterator beginItr,   typename std::vector<T,A>::iterator endItr);
This is equivalent to inheriting vector and overloading its foo method, but expressed with compile-time polymorphism (aka templates).

Template polymorphism is resolved during compile time via specializations, run-time polymorphism (aka inheritance) is orthogonal and often undesirable at this level.
I am not even talking about STL. Sequence is somekind of container only for string and stream buffers (and maybe somewhere else, if you wanna play). I am talking about my own `Sequence` class, not about the STL one. :-)

The problem is that if I inhert the base class and if that class has some methods that return some new objects of the same class, return type won't change if I inhert that base class. I mean if my base class is:
template< Type_ >
class Sequence{public:   Sequence< Type_ > Trim( .... );};


And my "child" is:
class String: public Sequence< char >{public:};


And when I create my new object:
String my_str;

my_str.Trim() will return Sequence< Type_ >, as we developers/programmers expected.

And here comes the problem. What should I do then? Should I encapsulate the object of the class Sequence< char > instead of inherting it? I am just confused right now, because making it virtual or inherting it will not solve the problem.

[Edited by - nerijus ramanauskas on March 16, 2010 9:35:57 AM]
Quote:Original post by nerijus ramanauskas
I am not even talking about STL. Sequence is somekind of container only for string and stream buffers (and maybe somewhere else, if you wanna play). I am talking about my own `Sequence` class, not about the STL one. :-)


And my reply was: "don't reinvent a completely solved problem".

Quote:The problem is that if I inherting the base class and if that class has some methods that return some new objects of the same class, return type won't change if I inherting that base class.


There is a reason why STL containers are not meant to be extended, and many lessons learned. They expose exactly what is fixed, and provide all additional functionality as free functions based on common interface (::iterators).

Quote:my_str.Trim() will return Sequence< Type_ >, as we developers/programmers expected.

This type of OO doesn't work all that well. Use in-place modification instead:
SomeSequenceType sst;trim(sst);// or, if original must be preservedtemplate < class T >T trimcopy(T source) {  T result = source;  trim(result);  return result;}


Since all of this is resolved during compile-time, there is no need for inheritance, typedefs will do, and they result in distinct types.

Quote:So that means it's quite efficient to make my template class methods virtual?

No, no inheritance, no virtuals, no nothing. Just plain old functions operating on templated types.

See how STL is defined and how <algorithm>s work.
Antheus, just noticed - this is it! (I thought you was talking only about some kinda STL containers, now I see it is just an example, isn't it?).
So that means it's quite efficient to make my template class methods virtual?
I think you want free functions. Read this article, about how free functions can increase encapsulation. You probably don't really want or need a "design pattern".
Quote:Original post by theOcelot
I think you want free functions. Read this article, about how free functions can increase encapsulation. You probably don't really want or need a "design pattern".

Ok, if, suppose, I want to overload the cast operator (operator signed int())?
.. So you all think that using free-functions is more efficient than using class-encapsulation? Oh, maybe: some "rich" templates and some "extensions" for it. Hmm... Yeah, baby! This is it! Thanks, finally realized that! ;-)
Quote:
Ok, if, suppose, I want to overload the cast operator (operator signed int())?

This is almost never a good idea. It can cause all sorts of subtle bugs.

This topic is closed to new replies.

Advertisement